应该在Java中的循环内部还是循环外部声明变量

web*_*per 4 java performance garbage-collection scope

我知道以前曾多次问过类似的问题,但是我仍然不确定对象何时可以使用GC,哪种方法更有效。

方法一:

for (Item item : items) {
    MyObject myObject = new MyObject();
    //use myObject.
}
Run Code Online (Sandbox Code Playgroud)

方法二:

MyObject myObject = null;
for (Item item : items) {
    myObject = new MyObject();
    //use myObject.
}
Run Code Online (Sandbox Code Playgroud)

我了解:“通过最小化局部变量的范围,可以提高代码的可读性和可维护性,并减少出错的可能性”。(约书亚·布洛赫)。

但是性能/内存消耗如何?在Java中,当对象没有剩余引用时,将收集垃圾。如果有例如100000个项目,则将创建100000个对象。在方法一中,每个对象都有一个引用(myObject),因此它们不符合使用GC的条件?

与方法二中的每次循环迭代一样,您要从上一次迭代中创建的对象中删除引用。因此,对象肯定会在第一次循环迭代后开始变得合格。

还是在性能与代码可读性和可维护性之间进行权衡?

我误会了什么?

注意:假设我关心性能,则循环后不需要myObject。

提前致谢

Rav*_*yal 5

如果有例如100000个项目,则将在方法1中创建100000个对象,并且每个对象都有一个引用(myObject),因此它们不适合使用GC?

不,从垃圾收集器的角度来看,这两种方法的工作原理相同,即没有内存泄漏。使用方法二,以下语句运行后

myObject = new MyObject();
Run Code Online (Sandbox Code Playgroud)

MyObject被引用的先前对象将成为一个孤立对象(除非在使用时将其Object传递给保存该引用的另一种方法),并且可以进行垃圾回收。

区别在于,一旦循环用完,您将MyObject可以通过myObject最初在循环外部创建的引用来访问最后一个实例。


GC是否知道在循环执行期间引用何时超出范围还是只能在方法结束时知道?

首先,只有一个参考,没有参考。是对象在循环中变得未引用。其次,垃圾收集不会自发启动。因此,请忘记循环,方法退出时甚至可能不会发生。

请注意,我说过,孤立对象可以使用gc,而不是立即收集它们。垃圾收集永远不会实时发生,而是分阶段进行。在标记阶段,所有不再通过活动线程无法访问的对象都标记为删除。然后,在清除阶段,将对存储器进行回收和附加压缩,就像对硬盘驱动器进行碎片整理一样。因此,它更像是批处理,而不是零碎的操作。

GC并不关心范围或方法本身。它仅查找未引用的对象,并且在需要时会这样做。你不能强迫它。您唯一可以确定的是,如果JVM内存不足,GC将会运行,但是您无法确切确定何时可以这样做。

但是,这一切确实等于说GC不能同时该方法执行或循环运行甚至在踢。例如,如果您有一个消息处理器,该消息处理器每10分钟左右处理10,000条消息,然后在它们之间进行睡眠,即Bean在循环内等待,进行10,000次迭代,然后再次等待;即使该方法尚未完成,GC肯定也会采取行动来回收内存。