Java 垃圾收集引用类

标签 java memory garbage-collection jvm heap-memory

我正在测试 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 引用的 Instances 是 softreachable,因此在由于剩余堆空间不足而真正需要 GC 时收集。代码第一个结果的左侧空间约为 150(可用内存 28 + 左侧最大内存 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 工作方式的理解是错误的。

请任何人告诉我原因。

谢谢^^

最佳答案

嵌入式问题最容易回答:如果你替换new Object()new StringBuffer(i)随着 i 的增加,您正在创建 StringBuffer容量不断增加的实例,因此这些对象比无状态对象需要更多内存也就不足为奇了 Object实例。

主要问题不是那么容易回答,因为您向我们展示了一个难以重现的结果,而在这期间又转向了一个更容易重现的结果,这表明您已经改变了更多代码比你说的要多,或者你的测试环境在两者之间有细微的变化。原则上,这两种结果都是可能的,但与您所做的更改完全无关。

首先,在您调用 System.gc() 时您持有对 ArrayList 的强烈引用在局部变量中,因此附加引用是弱引用还是软引用完全无关。在大多数设置和测试运行中,您将遇到 ArrayList并且包含的​​对象仍然占用内存。

但这并不是故事的结局。正如在 “finalize() called on strongly reachable object in Java 8” 中讨论的那样,如果 JVM 可以证明不会使用该引用,则即使持有强引用,对象也可以被收集。正如进一步讨论的那样,这是否会发生仅取决于 JVM 的优化状态和执行的代码,因此您的示例程序不太可能发生由唯一的 main 组成。通常在解释器中运行的方法,但并非不可能。

但如果发生这种情况,此逻辑适用于您的方法中所有 未使用的引用,其中包括对 SoftReference 的引用分别WeakReference实例。如果那个Reference对象本身被收集,它与所指对象的语义将再次无关紧要。然后,ArrayList ,包含的对象和引用对象被收集在一起。

如果您设置 sb变量为 null在调用之前显式 System.gc()并调用 get()在它之后的引用对象上,您可能会遇到不同的结果,但请记住,System.gc()仍然只是对 JVM 的提示,可能会被忽略,因此根本没有任何效果。

关于Java 垃圾收集引用类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36806008/

相关文章:

java - 华夫饼过滤器演示不起作用

java - 摆脱 "No Hibernate Session bound to thread"并在读取方法上使用 @Transactional 进行性能

c - g_object_new 应该有匹配的 g_object_unref 吗?

java - 显示依赖于区域设置的货币符号的最佳方式是什么?

c - 视频内存访问和后缀递增

c++ - 是否可以使用 ADODB::_RecordsetPtr 对象作为成员数据?

javascript - 关于闭包、LexicalEnvironment 和 GC

java - G1 收集器不执行完整 GC

用于垃圾回收的 Javascript 数组删除

java - 我遇到此错误 java.lang.IndexOutOfBoundsException : Index: 0, 大小:0