JVM的内存分配和垃圾回收机制

内存分配

JVM的内存可以分为堆内存和非堆内存,堆内存是进行垃圾回收的主要场所。堆内存分为年轻代和老年代,年轻代分为一个伊甸区和两个幸存区。
JVM的内存分配和垃圾回收机制
JVM的堆内存大小可以进行调节,默认是物理地址的1/64。最大分配的堆地址是1/4。
空余堆内存大小小于40%时,会自动调节堆内存大小到-Xmx设置的最大可分配堆内存。当空余内存大小大于70%,会自动下降内存大小到**-Xms设置的最小可分配堆内存**。为避免这种情况可将-Xmx的值和-Xms的值大小设为一致。通过参数**-Xmn2G** 可以设置年轻代大小为2G。通过**-XX:SurvivorRatio可以设置年轻代中Eden区与Survivor区的比值,设置为8,则表示年轻代中Eden区与一块Survivor的比例为8:1。
JVM非堆内存的大小使用-XX:PermSize 设置非堆内存初始值,默认是物理内存的1/64。由-XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
创建的对象会优先在Eden分配,如果是大对象(很长的字符串数组)则可以直接进入老年代。虚拟机提供一个-XX:PretenureSizeThreshold参数,令大于这个参数值的对象直接在老年代中分配,避免在Eden区和两个Survivor区发生大量的内存拷贝。长期存活的对象也会进入老年代,每一次MinorGC(年轻代GC),对象年龄就大一岁,默认15岁晋升到老年代,通过
-XX:MaxTenuringThreshold**设置晋升年龄。
Minor GC(年轻代GC):
对象优先在Eden中分配,当Eden中没有足够空间时,虚拟机将发生一次Minor GC,因为Java大多数对象都是朝生夕灭,所以Minor GC非常频繁,而且速度也很快。
Full GC(老年代GC):
Full GC是指发生在老年代的GC,当老年代没有足够的空间时即发生Full GC,发生Full GC一般都会有一次Minor GC。

动态对象年龄判定

如果Survivor空间中相同年龄所有对象的大小总和大于Survivor空间的一半,那么年龄大于等于该对象年龄的对象即可晋升到老年代,不必要等到-XX:MaxTenuringThreshold。

空间分配担保:

发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小。如果大于,则进行一次Full GC(老年代GC),如果小于,则查看HandlePromotionFailure设置是否允许担保失败,如果允许,那只会进行一次Minor GC,如果不允许,则改为进行一次Full GC。

垃圾回收

一个对象是否应该被回收,主要是看其是否还有引用。判断对象是否存在引用关系的方法包括引用计数法以及root根搜索方法。

引用计数法:

是一种比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只需要收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。

root根搜索方法:

root搜索方法的基本思路就是通过一系列可以做为root的对象作为起始点,从这些节点开始向下搜索。当一个对象到root节点没有任何引用链接时,则证明此对象是可以被回收的。以下对象会被认为是root对象:
栈内存中引用的对象
方法区中静态引用和常量引用指向的对象

被启动类(bootstrap加载器)加载的类和创建的对象
Native方法中JNI引用的对象。