[英]Java Garbage Collecting Reference Classes
我正在测试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引用的实例是softreachable,因为缺少剩余堆空间而在真正需要GC时收集。 代码的第一个结果的左侧空间大约是150(自由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
为什么这个不同?
最后,我再次运行代码修改:from
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的工作方式的理解是不正确的。
请有人告诉我原因。
Thx ^^
嵌入的问题是最简单的回答:如果你更换new Object()
用new StringBuffer(i)
与提高i
,要创建StringBuffer
情况下与能力越来越强,因此它不应该在一个惊喜来了,这些对象需要多少比无状态Object
实例更多的内存。
主要问题不是那么容易回答,因为你向我们展示了一个难以重现的结果,并且中间变成了一个更容易重现的结果,这表明你的代码中的变化比你更多已经说过或者你的测试环境有细微的变化。 原则上,这两种结果都是可能的,但与您所做的改变完全无关。
首先,当您调用System.gc()
您在局部变量中持有对ArrayList
的强引用,因此无论其他引用是弱还是软,都是完全无关紧要的。 在大多数设置和测试运行中,您将体验到ArrayList
并且所包含的对象仍占用内存。
但这不是故事的结局。 正如在“在Java 8中调用强可访问对象的finalize()”中所讨论的,即使存在强引用,如果JVM可以证明不会使用此引用, 也可以收集对象。 正如进一步讨论的那样,这是否会发生仅仅取决于JVM的优化状态和执行的代码,所以你的示例程序很可能不会发生,它由一个通常在解释器中运行的唯一main
方法组成,但这并非不可能。
但如果发生这种情况,此逻辑将应用于方法中所有未使用的引用,其中包括对SoftReference
resp的SoftReference
。 WeakReference
实例。 如果该Reference
对象本身被收集,它对指示对象的语义将再次无关紧要。 然后,收集ArrayList
,包含的对象和引用对象。
如果在调用System.gc()
之前显式地将sb
变量设置为null
并在之后的引用对象上调用get()
,则可能会遇到不同的结果,但请记住, System.gc()
仍然只是一个提示到JVM并且可以被忽略,因此完全没有效果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.