Java - 未引用的阵列仍然占用内存
我目前正在优化我的应用程序,并且我注意到它占用了近1G内存。我做了一些分析,发现问题: 我通过在我制作的纹理类中创建保存像素数据的int数组来分配大量内存。 但是这让我感到困惑,因为当创建一个新的数组时,旧的数组不再被使用,并且没有任何地方引用它。Java - 未引用的阵列仍然占用内存
我已经写了重新产生此问题的测试程序:
public class Main {
static class ArrayHolder {
int[] array;
void init() {
array = null;
array = new int[4000];
}
}
public static void main(String[] args) {
ArrayHolder holder = new ArrayHolder();
for (int i = 0; i < 1000000; i++) {
holder.init();
}
System.out.println(holder.array.length);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
当我运行这段代码的程序使用最多的RAM 600兆字节。我不明白为什么,因为在ArrayHolder中调用init()方法时,数组字段被设置为新数组,并且旧数组的引用丢失。这并不意味着它不再占用空间了吗? 对不起,如果这是一个没有问题的问题,但有人可以解释这是为什么,我在这里做错了什么?
array
是参考到Java中的数组。在这方面,它们像来自java.lang.Object
的任何其他常规对象。一旦不再有对一个数组的引用,它就会被安排进行垃圾收集,这不一定会立即发生。
释放内存中的这种延迟不太可能导致您的麻烦:垃圾收集器将在需要时收集未提交的对象。
请注意,即使垃圾收集器确实运行了,但仍无法保证进程将内存交还给操作系统,否则操作系统将从进程中夺回内存。
谢谢你指出。你如何着手减少这个特定例子的内存使用量?或者你会把它留给GC?因为对于简单的应用程序来说1演出似乎有点太过分了。 – RagingRabbit
我只会信任GC。 1GB在我的192GB机器上仅仅是微不足道的,因此如果CPU繁忙,1GB的尖峰不足以触发我盒子上的GC。 – Bathsheba
我使用JVisualVM再次运行程序,并使用它执行垃圾回收,但内存使用情况未发生变化。 GC是否决定不收集或是一个问题? – RagingRabbit
仅仅因为你的对象没有引用并不意味着它不会占用任何内存。 GC必须运行,然后才能从内存中“移除”。你可以在内存中没有引用的对象占用空间。检查GC是否已经运行,如果没有明确调用它(不是一个好主意)。此外,我建议您查找是否确实有一些对象的强引用。
您使用System.gc()
明确调用GC。
您可以添加诸如'-XX:+ PrintGCDetails'之类的JVM参数来检查GC是否已经运行。
他将如何检查垃圾收集器是否运行,以及如何调用它,以及为什么他不应该这样做? – bleistift2
@ bleistift2 - 编辑我的答案,添加你所需要的。至于为什么调用GC明确不是一个好主意,去低谷http://stackoverflow.com/questions/66540/when-does-system-gc-do-anything – TheLostMind
请注意'System.gc()'是咨询。 – Bathsheba
您的旧阵列只能在gc的判断下启动。如果gc在重新分配内存后很快运行,那么该空间将被回收,否则它不会。 – SMA
大型阵列被添加到终身空间,并且只有填满时才会默认进行GC编辑。例如睡眠不会触发GC。简而言之,像这样创建大量的大型数组很不理想,原因很多。 –