简体   繁体   English

Java SoftReference保证失败

[英]Java SoftReference guarantee failing

The JDK 7 documentation has this to say about a SoftReference : JDK 7文档有关于SoftReference说法:

"All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError." “在虚拟机抛出OutOfMemoryError之前, 保证可以清除对软可访问对象的所有软引用。”

However, in my test program, I'm seeing OutOfMemoryError consistently (except for the 'Stranger Behavior' section below) : 但是,在我的测试程序中,我一直看到OutOfMemoryError (除了下面的'Stranger Behavior'部分)

// RefObjectTest.java

import java.util.*;
import java.lang.ref.*;

public class RefObjectTest {

    public static void main(String[] args) {

        ArrayList<byte[]> leaks = new ArrayList<>();

        byte[] obj = new byte[10 * 1024 * 1024];

        SoftReference<byte[]> ref = new SoftReference<>(obj);

        // WeakReference is supposed to be eagerly GC'ed, but I see no
        // difference in terms of program behavior: still get OOME.
        //
        // WeakReference<byte[]> ref = new WeakReference<>(obj);

        obj = null;

        while(true) {
            byte[] x = ref.get();
            if(x == null) {
                System.out.println("Referent stands garbage collected!!");
                break;
            } else {
                System.out.println("Referent still alive.");
            }

            // Leak memory in small, 10k increments. If soft reference
            // worked the way it's advertized, then just before the OOME, the 
            // 10MB referent should have been GC'ed to accomodate this small
            // 10K new memory request. But it doesn't appear to work that way!

//          try {
                leaks.add(new byte[10 * 1024]);
//          } catch(OutOfMemoryError e) {
//              System.out.println(ref.get() == null ? "Referent cleared" : 
//                  "Referent still alive");
//          }

            // VERY STRANGE: If I re-instate the above try-catch block, then no OOME is
            // thrown, and the program keeps printing "Referent still alive" lines
            // forever until I finally kill it with a Ctrl+C.

            // Uncommenting gc() tends to delay the OOME in terms of time, 
            // but OOME eventually does happen, and after the same number of
            // iterations of this loop. 
            // 
            // System.gc();
        }
    }
}

Here's the output: 这是输出:

$ java -Xmx15m RefObjectTest
Referent still alive.
  ...
Referent still alive.
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at RefObjectTest.main(RefObjectTest.java:38)

Stranger Behavior 陌生人的行为

What is VERY STRANGE is, if I re-instate the try-catch block, the program appears to run fine forever, printing "Referent still alive." 什么是非常奇怪的是,如果我重新启动try-catch块,该程序似乎永远运行正常,打印“Referent仍然活着”。 lines until I get tired and kill it. 直到我累了并杀了它。

$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
$ 
$ uname -a
Linux ida 3.10.11-100.fc18.x86_64 #1 SMP Mon Sep 9 13:06:31 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

What am I missing in all of this? 我在这一切中缺少什么?

It's not strange at all, the allocation is failing which is throwing an exception. 这一点都不奇怪,分配失败就是抛出异常。 By catching the exception you are saying that the program can continue, by not catching the exception you are saying that you can't handle it and the program exits. 通过捕获异常,你说程序可以继续,通过不捕获异常,你说你无法处理它并退出程序。

Inside your while loop you are doing: 在你的while循环中你正在做:

        byte[] x = ref.get();

This is creating a new Strong reference from your Soft Reference. 这是从您的软参考创建一个新的强引用。 As soon as you do that it is no longer eligible for collection. 一旦你这样做,它就不再有资格收集。 You don't clear that Strong Reference before you go on to do the new allocation. 在继续执行新分配之前,您不会清除强引用。

Do x = null after you have done the test. 完成测试后, x = null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM