Java垃圾收集引用类

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

我正在测试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);
}
我取消了对“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的内存。其中as
new 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