Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak in weakValue map reference for synchronized method

I am creating an interface for executing methods concurrently, while abstracting away the synchronization details (To swap for a distributed implementation when needed). I've created a single jvm implementation that allows Strings to be used as the mutex by storing them in a map to ensure one reference is used, even if Strings of different references are passed in. The concurrency seems to work fine, however I was surprised to see that the test was showing the reference count is never decreasing. I assumed using WeakValues() would be enough to prevent memory leaks, but it seems that is not the case. Can anyone point out what could be causing this leak?

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();
    } 
}

}

Here is the test that is failing at the very last assertion:

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);        
        }

    };
}

}

This last assertion is what breaks the test: assertEquals(0, methodExecutor.mutexMap.size());

like image 969
Anthony DePalma Avatar asked Jun 21 '11 01:06

Anthony DePalma


2 Answers

You're storing the exact same String object as both the key and the value. The key is a strong reference to the object, and as long as a strong reference to it exists, the weak reference to it is meaningless. The definition of weakly reachable (here) states that:

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

By the way, even with this corrected I don't think you can assume that the map will always be empty at the end. It will probably be close to empty, but I think that's all that can be said about it.

like image 187
ColinD Avatar answered Oct 22 '22 09:10

ColinD


Weak references will only be collected when the JVM absolutely needs more memory.

like image 21
Jack Edmonds Avatar answered Oct 22 '22 11:10

Jack Edmonds