我知道很多人之前已经问过这个问题,但我的重点不在于性能,而在于操作的内存占用。
考虑以下虚拟类:
public class MemoryDemo implements Runnable{
private boolean run;
public MemoryDemo(){
run = true;
}
@Override
public void run(){
byte[] wbuffer; //Here
final int n = ... //Some big quantity in order of millions.
while(run){
//byte[] wbuffer; or here?
wbuffer = new byte[n]; //Reallocate every loop? or just keep the same memory?
//Do stuff with the byte array here
//Copies the data to the target buffer (Not shown here, from another class)
System.arraycopy(wbuffer, 0, n, targetbuffer, 0, wbuffer.length);
}
}
}
我知道来自here和here人们说它在性能方面完全没有区别,而且有限的范围是更好的方法,但内存占用情况如何呢?
如果从上面观察,你可以看到我正在分配一些相当大的数组,并且由于java没有删除函数/构造,我们必须依靠垃圾收集器来释放内存。在我的应用程序中,我有几个这些循环(它基本上是一个实时图像处理管道)我希望尽可能地减少内存占用(即帮助GC以最佳方式完成它的工作)。
哪个,在循环内部或循环声明之外,如果有的话,在垃圾收集方面更好?我知道如果不再引用它,GC只能释放内存但是我不清楚如果重新分配一个变量会发生什么(即当循环重新启动并再次分配wbuffer
对象时)。由于内部循环变量丢失了它的整个引用,它是否先收集垃圾?或者,当变量重新分配时,它们是否都会收集垃圾?我应该在每个循环结束时调用System.gc();
吗?
另外,假如我的代码可以写入字节数组中的所有字节,那么如果我永远不会重新分配变量(因为我从不在循环中调用新的byte [n]),不会重新分配字节数组更好的方法(一个更丑陋的......)?
NB不重新分配数组对我来说可能不是一个可行的选择(对于我所有的类)如果它确实是最好的选择,请解释哪个是第二好的(内部/外部循环或没有区别) !
答案 0 :(得分:4)
从内存角度来看,重要的是确定对象何时有资格进行垃圾回收。
在您的情况下,它没有区别:只要您编写wbuffer = new byte[n];
,前一个字节数组就无法访问,因此符合GC条件。
重用相同的数组会增加内存占用,在这种情况下,您需要在循环之前声明它。
GC将在必要时运行。除了非常具体的用例之外,调用System.gc();
通常是一个坏主意 - 它实际上可能会对性能产生负面影响。
答案 1 :(得分:1)
您误解了与之相关的问题。
在这些问题中,问题是变量已定义,但分配的对象数量没有变化。所以,它并没有影响性能。
但在
之间byte[] wbuffer = new byte[size];
for (....) {
}
和
for (....) {
byte[] wbuffer = new byte[size];
}
存在内存和性能差异。
在第二个对象中创建了更多对象,这会同时影响性能和内存。
您搜索的问题说明第二种形式和
之间没有区别byte[] wbuffer;
for (...) {
wbuffer = new byte[size];
}
答案 2 :(得分:0)
无论你在循环内部还是外部声明byte[] wbuffer;
,它都不会有太大的区别,因为它只是一个引用变量。
主内存分配发生在这里wbuffer = new byte[n];
,现在如果你在每次循环迭代中创建新数组,那么GC肯定会很高。
如果不知何故你可以在每个循环迭代中使用相同的数组,那么你肯定会节省内存,否则即使你在这里和那里随机播放,性能也没有真正的差别。
答案 3 :(得分:0)
您不应该重新分配每个循环。 而且你不应该每次都运行垃圾收集。
但实际上它并没有大不同。
答案 4 :(得分:0)
JVM的垃圾收集完全不可预测。不同的实现可能会有不同的执行,而Oracle的JVM本身就有多个垃圾收集器策略。
幸运的是,您正在使用原始数组。这使得事情变得相当复杂。如果只调用new一次,则只创建一个数组。即使通过System.arrayCopy编辑数组中的值,实际上也会编辑这些值而不是创建新数组。如果在循环外声明数组,垃圾收集甚至不会进入等式。
答案 5 :(得分:0)
将声明变量放在循环内部或外部是没有意义的,因为您在每次迭代时都重新分配它。可能在这种情况下,您需要一个干净的零初始化字节数组,因此只有在不重用相同的字节数组时才使它在循环外部才有意义。