【发布时间】:2016-08-16 19:17:29
【问题描述】:
我正在测试 gc 如何与 java.lang.ref 包中的类一起工作,仅供学习:)
以下是我的代码。
public static void main(String [] args) {
int mb = 1024*1024;
//Getting the runtime reference from system
Runtime runtime = Runtime.getRuntime();
System.out.println("##### Heap utilization statistics [MB] #####");
ArrayList<Object> sb = new ArrayList<Object>();
for(int i =0; i < 5000000; i++){
sb.add(new Object());
if( i % 1000 == 0) {
System.out.println(i);
}
}
SoftReference<ArrayList> wr = new SoftReference<ArrayList>(sb);
// System.gc()
//Print used memory
System.out.println("Used Memory:"
+ (runtime.totalMemory() - runtime.freeMemory()) / mb);
//Print free memory
System.out.println("Free Memory:"
+ runtime.freeMemory() / mb);
//Print total available memory
System.out.println("Total Memory:" + runtime.totalMemory() / mb);
//Print Maximum available memory
System.out.println("Max Memory:" + runtime.maxMemory() / mb);
}
结果:
Used Memory:95,
Free Memory:28,
Total Memory:123,
Max Memory:247
我撤消了对“System.gc()”的注释,重新运行代码,结果是
Used Memory:1,
Free Memory:122,
Total Memory:123,
Max Memory:247
是的,首先收集ArrayList的实例。据我所知,仅由 SoftReference 引用的实例是可软访问的,因此在由于缺少剩余堆空间而真正需要 GC 时进行收集。代码的第一个结果的剩余空间约为 150(free mem 28 + left max mem 124)。我不明白为什么要收集 ArrayList 的实例。
其次,我通过修改运行代码:
sb.add(new Object()); -> sb.add(new StringBuffer(i));
结果:
Used Memory:245,
Free Memory:2,
Total Memory:247,
Max Memory:247
为什么不一样??
最后,我再次运行代码并进行了修改: 来自
SoftReference<ArrayList> wr = new SoftReference<ArrayList>(sb);
到
WeakReference<ArrayList> wr = new WeakReference<ArrayList>(sb);
结果:
Used Memory:245,
Free Memory:2,
Total Memory:247,
Max Memory:247
我猜想 ArrayList 的实例是被收集的,因为这些实例只被 WeakReferece 引用,所以这些都是弱可达的。但他们没有被收集。
我现在假设我对 Reference 工作方式的理解是不正确的。
请任何人告诉我原因。
谢谢^^
【问题讨论】:
-
这不可能是您实际运行的代码。由于您从不删除
sb引用本身,因此肯定不会收集ArrayList。您不是刚刚在第二次和第三次测试之间删除了一些sb = null;行吗? -
首先 gc 不会删除仍然有引用的对象。而且您永远无法确定 System.gc() 是否会运行,这取决于 jvm。
-
正如 Dolda 所指出的,您强烈引用了
ArrayList。如果有的话,您看到的差异可能是由于ArrayList反复调整自身大小,这会在循环期间分配逐渐更大的数组。 (这些数组就是被垃圾收集的东西。)另外,我不确定我是否理解你关于StringBuffer的问题。StringBuffer比普通的Object大得多,因为它里面有一个数组。因此,不应该期望它使用更多的内存吗? -
请不要使用StringBuffer,因为它在十多年前就被替换了。这会使用很多更多内存,因为您在其中保留了一个非常大的
char[]。 -
如果您使用
new StringBuffer(i),其中i接近5000000,那么每个缓冲区 将使用大约10 MB。new Object()将使用大约 16 个字节,即使对于i的大值。
标签: java memory garbage-collection jvm heap-memory