4

免责声明:请不要提供有关过早优化的建议。我只是好奇。

想象一下,我想确保字段引用的某些对象可以尽快被垃圾回收。我正在使用这样的自制单链表

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;
}

我在这里看不到任何缺点,它使所有对象都可以在原始代码中立即收集。

4

1 回答 1

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字段或可能分配内存等的代码,则将在每次调用之前执行字段存储。

于 2013-10-23T17:26:15.487 回答