java - 同步方法的 weakValue 映射引用中的内存泄漏

标签 java memory memory-leaks synchronization concurrent-collections

我正在创建一个用于并发执行方法的接口(interface),同时抽象出同步细节(在需要时交换分布式实现)。我创建了一个单独的 jvm 实现,通过将字符串存储在映射中以确保使用一个引用,允许将字符串用作互斥量,即使传入不同引用的字符串也是如此。并发似乎工作正常,但我是惊讶地看到测试显示引用计数从未减少。我假设使用 Wea​​kValues() 就足以防止内存泄漏,但事实似乎并非如此。任何人都可以指出可能导致此泄漏的原因吗?

public class SynchronousMethodExecutorSynchronizedImpl implements ISynchronousMethodExecutor {

// mutex map to provide string references
final Map<String, String> mutexMap = new MapMaker()
    .weakValues()
    .makeComputingMap(
        new Function<String, String>() {
        @Override
        public String apply(String id) {
            return id;
        }
    });

@Override
public Object doSynchronousMethod(String domain, String id, ISynchronousMethod synchronousMethod) {
    synchronized(mutexMap.get(domain + "." + id))
    {
        return synchronousMethod.execute();
    } 
}

这是在最后一个断言处失败的测试:

public class SynchronousMethodExecutorSynchronizedImplTest extends TestCase {
int counter;
SynchronousMethodExecutorSynchronizedImpl methodExecutor;

@Override
public void before() throws Exception {
    super.before();

    methodExecutor = new SynchronousMethodExecutorSynchronizedImpl();
}

@Test
public void concurrentExecute() throws InterruptedException {
    assertEquals(0, counter);

    for(int i=0; i<1000; i++)
        getConcurrentExecutorThread().start();

    // wait for threads to complete
    Thread.sleep(1000);

    assertEquals(1, methodExecutor.mutexMap.size());

    try
    { 
        final List<long[]> infiniteList = new LinkedList<long[]>(); 

       for(long i = Long.MIN_VALUE; i < Long.MAX_VALUE; i++)
            infiniteList.add(new long[102400]); 

        fail("An OutOfMemoryError should be thrown");
    } 
    catch(OutOfMemoryError e)
    { 

    }

    assertEquals(2000, counter);
    assertEquals(0, methodExecutor.mutexMap.size());
}

// synchronous method
private ISynchronousMethod method = new ISynchronousMethod() {
    @Override
    public Object execute() {
        counter++;  
        return null;
    }
};

/**
 * Executes a line of code.
 * 
 * @return Thread
 */
private Thread getConcurrentExecutorThread() {
    return new Thread() {
        @Override
        public void run() {
            methodExecutor.doSynchronousMethod("TEST", "1", method);
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {

            }
            methodExecutor.doSynchronousMethod("TEST", new String("1"), method);        
        }

    };
}

最后一个断言破坏了测试: assertEquals(0, methodExecutor.mutexMap.size());

最佳答案

您正在存储与键和值完全相同的 String 对象。关键是对象的强引用,只要强引用存在,弱引用就没有意义。 弱可达 ( here ) 的定义指出:

An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference.

顺便说一下,即使修正了这个问题,我也不认为你可以假设 map 最后总是空的。它可能几乎是空的,但我认为这就是关于它的全部内容。

关于java - 同步方法的 weakValue 映射引用中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6419279/

相关文章:

使用 LinkedBlockingQueue 时的 Java 内存泄漏

memory-leaks - WP8 LongListSelector内存泄漏

java - 名称类需要完整路径,仅使用类名无法找到 - android

java - Hibernate 对象在 AngularJS 和 Spring 中作为 @RequestBody

java - JUnit 封闭式​​运行器和共享设置

c - stack smashing后报错信息怎么办

java - Jpa 存储库查询不起作用

memory - Ubuntu 32 位最大地址空间

c++ - "smart pointer"代码会泄漏内存吗?

android - 在 onDestroy() 上从 View 中解除绑定(bind)可绘制对象