如何让java系统发布Soft References?

JBM*_*JBM 17 java caching soft-references

我将使用基于SoftReference的缓存(一个非常简单的事情).但是,我在为它编写测试时遇到了一个问题.

测试的目的是检查缓存是否在内存清理发生后再次从服务器请求先前缓存的对象.

在这里,我找到了如何使系统释放软引用对象的问题.调用System.gc()是不够的,因为在内存不足之前不会释放软引用.我正在PC上运行此单元测试,因此VM的内存预算可能非常大.

==================后来添加==============================

谢谢所有照顾的人!

考虑到所有职业选手和反对者后,我决定按照nandajarnbjo的建议采取蛮力方式.然而,似乎JVM并不是那么愚蠢 - 如果你要求一个比VM的内存预算更大的块,它甚至都不会尝试垃圾收集.所以我修改了这样的代码:

    /* Force releasing SoftReferences */
    try {
        final List<long[]> memhog = new LinkedList<long[]>();
        while(true) {
            memhog.add(new long[102400]);
        }
    }
    catch(final OutOfMemoryError e) {
        /* At this point all SoftReferences have been released - GUARANTEED. */
    }

    /* continue the test here */
Run Code Online (Sandbox Code Playgroud)

Dav*_*eot 13

这段代码强制JVM刷新所有SoftReferences.这样做很快.

它比Integer.MAX_VALUE方法更好用,因为这里JVM确实试图分配那么多内存.

try {
    Object[] ignored = new Object[(int) Runtime.getRuntime().maxMemory()];
} catch (OutOfMemoryError e) {
    // Ignore
}
Run Code Online (Sandbox Code Playgroud)

我现在在需要使用SoftReferences单元测试代码的地方使用这一段代码.

更新:这种方法确实只能用于少于2G的最大内存.

另外,需要非常小心SoftReferences.错误地保留一个硬引用很容易否定SoftReferences的影响.

这是一个简单的测试,显示它每次都在OSX上工作.有兴趣知道JVM在Linux和Windows上的行为是否相同.


for (int i = 0; i < 1000; i++) {
    SoftReference<Object> softReference = new SoftReferencelt<Object>(new Object());
    if (null == softReference.get()) {
        throw new IllegalStateException("Reference should NOT be null");
    }

    try {
        Object[] ignored = new Object[(int) Runtime.getRuntime().maxMemory()];
    } catch (OutOfMemoryError e) {
        // Ignore
    }

    if (null != softReference.get()) {
        throw new IllegalStateException("Reference should be null");
    }

    System.out.println("It worked!");
}
Run Code Online (Sandbox Code Playgroud)


emm*_*mby 5

这项改进适用于最大内存超过 2G 的情况。它会循环直到发生 OutOfMemory 错误。

@Test
public void shouldNotHoldReferencesToObject() {
    final SoftReference<T> reference = new SoftReference<T>( ... );

    // Sanity check
    assertThat(reference.get(), not(equalTo(null)));

    // Force an OoM
    try {
        final ArrayList<Object[]> allocations = new ArrayList<Object[]>();
        int size;
        while( (size = Math.min(Math.abs((int)Runtime.getRuntime().freeMemory()),Integer.MAX_VALUE))>0 )
            allocations.add( new Object[size] );
    } catch( OutOfMemoryError e ) {
        // great!
    }

    // Verify object has been garbage collected
    assertThat(reference.get(), equalTo(null));

}
Run Code Online (Sandbox Code Playgroud)


Rub*_*ben 0

您可以在测试中显式地将软引用设置为 null,并因此模拟软引用已被释放。

这避免了任何依赖于内存和垃圾收集的复杂测试设置。