聊聊Java垃圾回收:什么时候回收?
发布网友
发布时间:2024-12-09 14:23
我来回答
共1个回答
热心网友
时间:2024-12-09 14:44
探讨Java垃圾回收的时机,首先需理解JVM内存分配机制。JVM堆内存被分为新生代、老年代以及永久代。按照新生代与老年代的垃圾回收策略,可大致分为:
新生代GC(Minor GC):频繁发生于新生代,因Java对象多数具有“瞬生瞬灭”的特性,故速度较快。
老年代GC(Major GC / Full GC):发生在老年代,Major GC通常伴随至少一次Minor GC,速度明显慢于Minor GC。
对象倾向于在Eden区分配
大部分情况下,对象在新生代Eden区分配。当Eden区空间不足时,JVM将发起一次Minor GC。
大对象直接进入老年代
所谓大对象需要大量连续内存空间,如长字符串或数组。大对象对内存分配是一个不利因素,常导致内存使用接近极限时提前触发垃圾收集,以获取连续空间。
虚拟机提供了-XX:PretenureSizeThreshold参数,允许大于该值的对象直接在老年代分配,以减少内存复制。
PretenureSizeThreshold参数适用于Serial和ParNew收集器,Parallel Scavenge收集器不支持此参数。
长期存活对象进入老年代
为识别对象应放置的内存区域,JVM通过对象年龄计数器实现。对象在Survivor区存活并能被容纳,年龄设为1。对象年龄随Minor GC增加,当达到特定值(默认为15岁)时,对象将晋升至老年代。年龄阈值可通过-XX:MaxTenuringThreshold参数设置。
动态对象年龄判定
为适应不同程序的内存状况,JVM允许在Survivor区空间不足时,直接将年龄满足条件的对象晋升至老年代,而无需达到MaxTenuringThreshold。
空间分配担保
在执行Minor GC前,JVM检查老年代最大可用连续空间是否足够新生代对象总空间。如不满足,虚拟机评估是否允许担保失败,以决定是否执行Minor GC或Full GC,以确保内存回收安全。
“冒险”意味着担保失败的可能性,当大量对象在Minor GC后仍存活,可能导致老年代分配失败,需要执行Full GC以腾出空间。为避免担保失败过于频繁,通常开启HandlePromotionFailure开关。