免责声明:请不要提出有关过早优化的建议。我很好奇。
想象一下,我想确保一个字段引用的某些对象可以尽快被垃圾收集。我正在使用像这样的自制单链表
class BigData {
byte[] someBigArray;
BigData next;
}
private BigData bigData;
并像这样迭代
while (bigData != null) {
process(bigData);
bigData = bigData.next;
}
JIT是否可以随意改变它?
BigData tmp = bigData;
while (tmp != null) {
process(tmp);
tmp = tmp.next;
}
bigData = null;
假设没有其他任何BigData
实例的引用。假设process
是一种不能访问字段bigData
的简单内联方法。两个片段都是等效的(假设没有异常被抛出),唯一的区别是第二个片段将字段访问从循环移动到外部。
重申免责声明:请不要提出有关过早优化的建议。我很好奇。
回答评论“即使你想要的改变是JIT的作用,为什么GC会更快/更快地收集它们?”:如果JIT做了改变,然后,所有大对象只能在循环后收集。如果没有,那么每次循环前进一个对象就有资格获得GC。
实际上,只要JIT可以自由地进行上述转换,它就可以做到这一点:
BigData tmp = bigData;
bigData = null;
while (tmp != null) {
process(tmp);
tmp = tmp.next;
}
我在这里看不到任何不利之处,它使所有对象在原始代码中尽快收藏。
答案 0 :(得分:2)
好的,优化器可以优化
while (bigData != null) {
process(bigData);
bigData = bigData.next;
}
到
BigData tmp = bigData;
while (tmp != null) {
process(tmp);
tmp = tmp.next;
}
bigData = null;
如果bigData
字段不是volatile
且process
方法没有禁止此优化的副作用。
但实际上,代码转换(如果有的话)看起来会完全不同。通常情况下,优化器会循环展开,创建执行一定次数迭代的代码块,并在进行向后跳转之前执行字段存储操作。因此垃圾收集器可以跳入某些“保存点”。但是如果process
方法包含访问bigData
字段的代码或者可能分配内存等,则会在每次执行之前执行字段存储调用