这是一个稍微不同的示例,其中包含最终引用类型字段而不是最终值类型局部变量:
public class MyClass {
public final MyOtherObject obj;
}
每次创建MyClass实例时,都将创建对MyOtherObject实例的传出引用,GC必须遵循该链接来查找活动对象。
JVM使用标记扫描GC算法,该算法必须检查GC“根”位置中的所有实时裁判(如当前调用堆栈中的所有对象)。每个活动对象都被“标记为”活动,活动对象所引用的任何对象也都被标记为活动。
标记阶段完成后,GC会扫描整个堆,为所有未标记的对象释放内存(并为剩余的活动对象压缩内存)。
同样,重要的是要认识到Java堆内存被划分为“年轻”和“旧”。所有对象最初都是在年轻一代中分配的(有时称为“托儿所”)。由于大多数对象都是短命的,因此GC在从年轻一代释放最新垃圾方面更加积极。如果某个对象在年轻一代的收集周期中幸存下来,则将其移入旧一代(有时称为“终身一代”),该对象的处理频率较低。
因此,我想说的是:“不,'最终'修饰语无法帮助GC减少工作量”。
我认为,在Java中优化内存管理的最佳策略是尽快消除虚假引用。您可以通过在使用完对象后立即为对象引用分配“ null”来做到这一点。
或者更好的是,最小化每个声明范围的大小。例如,如果您在1000行方法的开头声明了一个对象,并且该对象在该方法作用域关闭之前(最后一个大括号)一直保持活动状态,则该对象可能会存活更长的时间必要。
如果您使用小的方法,只有十几行代码,则在该方法中声明的对象将更快地超出范围,并且GC将能够在效率更高的范围内完成其大部分工作年轻一代。除非绝对必要,否则您不希望将对象移入较早的一代。