在 Java 中对变量使用 final 会改善垃圾收集吗?
今天我和我的同事讨论了在 Java 中使用 final
关键字来改进垃圾收集.
Today my colleagues and me have a discussion about the usage of the final
keyword in Java to improve the garbage collection.
例如,如果您编写一个方法,例如:
For example, if you write a method like:
public Double doCalc(final Double value)
{
final Double maxWeight = 1000.0;
final Double totalWeight = maxWeight * value;
return totalWeight;
}
在方法final
中声明变量将有助于垃圾回收在方法退出后从方法中未使用的变量中清理内存.
Declaring the variables in the method final
would help the garbage collection to clean up the memory from the unused variables in the method after the method exits.
这是真的吗?
推荐答案
这里有一个稍微不同的例子,一个具有最终引用类型字段而不是最终值类型局部变量的示例:
Here's a slightly different example, one with final reference-type fields rather than final value-type local variables:
public class MyClass {
public final MyOtherObject obj;
}
每次创建 MyClass 实例时,都会创建对 MyOtherObject 实例的传出引用,并且 GC 必须通过该链接查找活动对象.
Every time you create an instance of MyClass, you'll be creating an outgoing reference to a MyOtherObject instance, and the GC will have to follow that link to look for live objects.
JVM 使用标记扫描 GC 算法,该算法必须检查 GC根"位置中的所有活动引用(就像当前调用堆栈中的所有对象一样).每个活动对象都被标记"为活动对象,活动对象引用的任何对象也被标记为活动对象.
The JVM uses a mark-sweep GC algorithm, which has to examine all the live refereces in the GC "root" locations (like all the objects in the current call stack). Each live object is "marked" as being alive, and any object referred to by a live object is also marked as being alive.
标记阶段完成后,GC 扫过堆,为所有未标记的对象释放内存(并为剩余的活动对象压缩内存).
After the completion of the mark phase, the GC sweeps through the heap, freeing memory for all unmarked objects (and compacting the memory for the remaining live objects).
此外,重要的是要认识到 Java 堆内存被划分为年轻一代"和老一代".所有对象最初都在年轻代(有时称为托儿所")中分配.由于大多数对象都是短暂的,GC 更积极地从年轻代中释放最近的垃圾.如果一个对象在年轻代的收集周期中存活下来,它就会被移入老年代(有时称为老年代"),而老年代的处理频率较低.
Also, it's important to recognize that the Java heap memory is partitioned into a "young generation" and an "old generation". All objects are initially allocated in the young generation (sometimes referred to as "the nursery"). Since most objects are short-lived, the GC is more aggressive about freeing recent garbage from the young generation. If an object survives a collection cycle of the young generation, it gets moved into the old generation (sometimes referred to as the "tenured generation"), which is processed less frequently.
所以,在我的脑海中,我要说不,'final' 修饰符不会帮助 GC 减少其工作量".
So, off the top of my head, I'm going to say "no, the 'final' modifer doesn't help the GC reduce its workload".
在我看来,在 Java 中优化内存管理的最佳策略是尽快消除虚假引用.您可以在使用完对象引用后立即将null"分配给它.
In my opinion, the best strategy for optimizing your memory-management in Java is to eliminate spurious references as quickly as possible. You could do that by assigning "null" to an object reference as soon as you're done using it.
或者,更好的是,最小化每个声明范围的大小.例如,如果您在 1000 行方法的开头声明一个对象,并且如果该对象在该方法的范围关闭(最后一个闭合花括号)之前保持活动状态,那么该对象可能会比实际保持活动更长时间必要的.
Or, better yet, minimize the size of each declaration scope. For example, if you declare an object at the beginning of a 1000-line method, and if the object stays alive until the close of that method's scope (the last closing curly brace), then the object might stay alive for much longer that actually necessary.
如果您使用只有十几行代码的小方法,那么在该方法中声明的对象将更快地超出范围,并且 GC 将能够在以下范围内完成大部分工作-更高效的年轻一代.除非绝对必要,否则您不希望将对象移入老一代.
If you use small methods, with only a dozen or so lines of code, then the objects declared within that method will fall out of scope more quickly, and the GC will be able to do most of its work within the much-more-efficient young generation. You don't want objects being moved into the older generation unless absolutely necessary.
相关文章