JVM常见知识点总结(一)

JVM常见知识点总结(一)

​ 在经历了两次翻看《深入理解Java虚拟机》之后,康康对JVM总算有了一个较为清晰的认识。本篇文章基于原书内容,对java虚拟机的知识点进行整理,便于复习查看。

一、运行时数据区域

1.线程私有:

a) 程序计数器:当前线程所执行的字节码的行号指示器。占用空间小,不会发生OOM

b) 虚拟机栈:每个方法被执行时,Java虚拟机会同步创建一个栈帧,用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每个方法调用直至执行完毕的过程对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

​ 局部变量表中保存了编译器可知的各种Java虚拟机基本数据类型、对象引用和returnAddress类型(指向了一条字节码指令的地址)

c)本地方法栈:与虚拟机栈类似,不过是为Native方法服务

2.线程共享

a)方法区:存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

​ 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池 具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。

b)堆:存储几乎所有的对象实例,通常占用最多的内存,经常发生垃圾回收。

二、简述垃圾回收机制

在 java 中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在 JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚 拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将 它们添加到要回收的集合中,进行回收。

三、GC对象判定机制

1.引用计数法:给每个对象设置一个引用计数器,每当有一个地方引用此对象,计数器加一,若引用失效,计数器减一。当引用计数器为零时,该对象被判定为“已死”,即将被回收

​ 引用计数法易于实现,但是存在循环引用导致内存泄露的问题,主流的虚拟机并没有采用引用计数法

2.可达性算法(引用链法):从GC Roots对象开始向下搜索,如果一个对象到GC Roots没有任何引用链时,说明此对象不可用。

​ GC Roots对象包括以下:

​ a)虚拟机栈中引用的对象

​ b)方法区中静态变量引用的对象

​ c)方法去中常量引用的对象

​ d)本地方法栈中JNI引用的对象

四、垃圾回收算法

1.标记-清除:

​ 这是垃圾收集算法中最基础的,根据名字就可以知道,它的思想就是标记哪些要被 回收的对象,然后统一回收。这种方法很简单,但是会产生大量不连续的内存碎片,导致以后程序在 分配较大的对象时,由于没有充足的连续内存而提前触发一次GC动作。

2.标记-复制

为了解决效率问题,复制算法将可用内存按容量划分为相等的两部分,然后每次只 使用其中的一块,当一块内存用完时,就将还存活的对象复制到第二块内存上,然 后一次性清楚完第一块内存,再将第二块上的对象复制到第一块。但是这种方式,内存的代价太高,每次基本上都要浪费一般的内存。

于是将该算法进行了改进,内存区域不再是按照 1:1 去划分,而是将内存划分为 8:1:1 三部分,较大那份内存交 Eden 区,其余是两块较小的内存区叫 Survior 区。 每次都会优先使用 Eden 区,若 Eden 区满,就将对象复制到第二块内存区上,然 后清除 Eden 区,如果此时存活的对象太多,以至于 Survivor 不够时,会将这些对 象通过分配担保机制复制到老年代中。

3.标记-整理

该算法主要是为了解决标记-清除,产生大量内存碎片的问题;当对象存活率较高 时,也解决了复制算法的效率问题。它的不同之处就是在清除对象的时候现将可回 收对象移动到一端,然后清除掉端边界以外的对象,这样就不会产生内存碎片了

4.分代收集

它根据对象的生存周期,将堆分为新生 代和老年代。在新生代中,由于对象生存期短,每次回收都会有大量对象死去,那 么这时就采用复制算法。老年代里的对象存活率较高,没有额外的空间进行分配担 保,所以可以使用标记-整理 或者 标记-清除

五、简述垃圾回收策略

1.对象优先在堆的Eden区域分配

2.大对象直接进入老年代

3.长期存活的对象逐步进入老年代

4.动态对象年龄判断

5.空间分配担保