如何在循环中创建对象而不浪费内存?

我已经完成了一个测试Java程序,看看在循环中使用“new”时Java的行为如何,我的结果非常糟糕。 这是该计划:

package test; public class Test { static int objectCount = 0; public static int getObjectCount() { return objectCount; } public Test() { objectCount++; } public void finalize() { objectCount--; } public static void main(String[] args) { int maxObjects = 0; long maxMemory = 0; long maxUsedMemory = 0; long maxFreeMemory = 0; long memory = 0; long usedMemory = 0; long freeMemory = 0; final long t0 = System.currentTimeMillis(); Test test = null; for (int i=0; i<10000000; i++) { System.gc(); test = new Test(); memory = Runtime.getRuntime().totalMemory(); freeMemory = Runtime.getRuntime().freeMemory(); usedMemory = memory - freeMemory; if (maxMemory < memory) maxMemory = memory; if (maxFreeMemory < freeMemory) maxFreeMemory = freeMemory; if (maxUsedMemory < usedMemory) maxUsedMemory = usedMemory; if (maxObjects < getObjectCount()) maxObjects = getObjectCount(); } final long t1 = System.currentTimeMillis(); System.out.println( "Maximum number of objects simultaneously allocated: "+ maxObjects); System.out.println("Max memory: " + maxMemory/1024/1024 + "MB"); System.out.println("Max used memory: " + maxUsedMemory/1024/1024 +"MB"); System.out.println("Max free memory: " + maxFreeMemory/1024/1024 +"MB"); System.out.println("Total Time: " + (t1 - t0)/60 + " secconds"); } } 

测试1:“System.gc();和test = new Test();” 评论说:

 Maximum number of objects simultaneously allocated: 0 Max memory: 123MB Max used memory: 0MB Max free memory: 122MB Total Time: 17 secconds 

测试2:“System.gc();” 评论说:

 Maximum number of objects simultaneously allocated: 8196834 Max memory: 696MB Max used memory: 485MB Max free memory: 343MB Total Time: 163 secconds 

测试3:没有评论,总迭代次数降至10000(从10000000):

 Maximum number of objects simultaneously allocated: 6 Max memory: 123MB Max used memory: 0MB Max free memory: 122MB Total Time: 974 secconds 

我相信这很糟糕,所以,这应该如何添加? 有什么办法可以防止这种情况吗?

更新:

测试2 whith -Xmx64M:

 Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded at test.Test.main(test.java:31) 

与128MB相同的结果。

测试2 whith -Xmx256M:

 (working...) (More than 21 minutes...) 

编辑取出所有使JIT工作更加困难并且运行verbose:gc -Xmx8m以下程序

 public class Test { public static void main(String[] args) { final long t0 = System.currentTimeMillis(); for (int i = 0; i < 100 * 10000000; i++) { Test test = new Test(); } final long t1 = System.currentTimeMillis(); System.out.println("Total Time: " + (t1 - t0) / 1000.0 + " secconds"); } } 

版画

 [GC (Allocation Failure) 1535K->424K(7680K), 0.0013697 secs] [GC (Allocation Failure) 1960K->384K(7680K), 0.0013561 secs] Total Time: 0.008 secconds 

注意:这是迭代计数的100倍。

如何在循环中创建对象而不浪费内存?

你不只是在浪费记忆而浪费你的工作。 注意:System.gc()比创建对象要贵几个数量级。

如果要优化循环,请在循环外创建对象。 但是,99%的情况下,您不需要这样做,实际上JIT具有Escape Analysis,它将对象的字段放在堆栈上并完全消除对象。

尝试使用-verbose:gc -Xmx32m运行它-verbose:gc -Xmx32m它创建了足够的对象来填充整个堆1000x然而

 public class EscapeAnalysisMain { public static void main(String[] args) { int i; for (i = 0; i < 2_000_000_000; i++) { Integer x = i; if (x.hashCode() < 0) throw new AssertionError(); } System.out.println(i); } } 

版画

 2000000000 

即20亿Integer对象,但没有足够的垃圾甚至一个集合。 怎么可能? 一旦代码变热, Integer对象全部放在堆栈而不是堆上,因此在此之后没有垃圾(除了最后一行)

如果创建Object,则会分配一些空间。 如果创建1000个对象,则分配1000 * x空间。

没有办法最小化Object的空间,解决方案是创建更少的对象或等待垃圾收集。