Java垃圾收集引用类
我正在测试gc如何处理java.lang.ref包中的类,只是为了研究:) 下面是我的代码Java垃圾收集引用类,java,memory,garbage-collection,jvm,heap,Java,Memory,Garbage Collection,Jvm,Heap,我正在测试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 utilizat
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);
}
我取消了对“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
Used Memory:245,
Free Memory:2,
Total Memory:247,
Max Memory:247
为什么这不一样
最后,我通过修改再次运行代码:
从
我猜ArrayList的实例是被收集的,因为这些实例只被WeakReference引用,所以它们是可以被WeakReache引用的。但它们没有被收集
我现在认为我对参考方法的理解是错误的
请告诉我原因
Thx^^嵌入的问题最容易回答:如果您将
new Object()
替换为new StringBuffer(i)
并增加i
,您将创建容量不断增加的StringBuffer
实例,因此,毫不奇怪,这些对象比无状态的对象
实例需要更多的内存
主要的问题并不是那么容易回答,因为您向我们展示了一个难以重现的结果,而在这两者之间,您又展示了一个更容易重现的结果,这表明您在代码中所做的更改比您所说的要多,或者您的测试环境在这两者之间发生了细微的变化。原则上,这两种结果都是可能的,但与您所做的更改完全无关
首先,在调用System.gc()
时,您在局部变量中持有对ArrayList
的强引用,因此附加引用是弱引用还是软引用完全无关。在大多数设置和测试运行中,您将体验到ArrayList
,其中包含的对象仍在占用内存
但这并不是故事的结局。如中所述,即使持有强引用,也可以收集对象,前提是JVM可以证明不会使用该引用。正如进一步讨论的那样,这是否会发生仅仅取决于JVM的优化状态和执行的代码,因此对于由通常在解释器中运行的唯一main
方法组成的示例程序来说,这是不太可能发生的,但这并非不可能
但如果发生这种情况,此逻辑将应用于方法中所有未使用的引用,其中包括对SoftReference
resp的引用<代码>WeakReference实例。如果Reference
对象本身被收集,那么它相对于referent的语义将再次不相关。然后,将ArrayList
、包含的对象和引用对象收集在一起
如果在调用
System.gc()
之前显式地将sb
变量设置为null
,然后在引用对象上调用get()
,您可能会遇到不同的结果,但请记住,System.gc()
仍然只是JVM的提示,可能会被忽略,因此根本没有效果。这不可能是您实际运行的代码。由于从未删除sb
引用本身,因此肯定不会收集ArrayList
。你不是刚刚删除了一些sb=null代码>第二次和第三次测试之间的行?第一件事是,如果对象仍然有引用,gc不会删除该对象。而且您永远无法确定System.gc()是否会运行,这取决于jvm。正如Dolda所指出的,您持有对ArrayList
的强烈引用。如果说有什么区别的话,那么您看到的差异可能是由于反复调整自身的大小,从而在循环过程中分配了越来越大的数组。(这些数组就是垃圾收集的对象。)另外,我不确定我是否理解您关于StringBuffer
的问题StringBuffer
比普通的对象大得多,因为它里面有一个数组。因此,它不应该使用更多的内存吗?请不要使用StringBuffer,因为它在十多年前就被替换了。这将使用更多的内存,因为您在其中保留了一个非常大的char[]
。如果您这样做new StringBuffer(i)
,其中i
接近5000000
,则每个缓冲区将使用大约10 MB的内存。其中asnew Object()
将使用大约16个字节,即使对于i
的大值也是如此。
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