In the following code:-
Set<Object> allObjects = new HashSet<>(1000);
while(...){ //really big loop - millions
Object s = getSomeObject();//returns a big object
allObjects.add(s);
if(allObject.size() == 1000){
//If allObjects has got big enough, process and proceed further
final Set<Object> allObjects_temp = new HashSet<>(allObjects); //--->a
allObject.clear();
//Process these objects in a separate tasks parallely
executerService.submit(new Runnable() {
public void run() {
processData(partner, allObjects_temp);//---->b
}
}));
}
}
Line-a will create new set with the elements copied from another set.
In line-b, these elements are being processed in another thread. However anonymous class is accessing the reference in outer class(Object s
) through allObjects_temp
, I believe Java GC will not be able to collect Objects created in the loop, even after the task has finished.
Will the Java GC in fact collect the Objects or not? If it will, please provide a brief explanation as to why it will. If it will be unable to collect the Objects, how can we fix this?
reference: When exactly is it leak safe to use (anonymous) inner classes?
Update: Wrote the following code to verify the memory leak. If no memory the code should run forever.
public class MemoryLeak {
public static void main(String[] args) {
ExecutorService executerService = new ThreadPoolExecutor(10, 10, 50, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(50, true), new ThreadPoolExecutor.CallerRunsPolicy());
Set<Object> allObjects = new HashSet<>(1500);
for (int i = 0; i < 100000;) { // really big loop - millions
Object s = getSomeObject();// returns a big object
allObjects.add(s);
if (allObjects.size() == 1500) {
// If allObjects has got big enough, process and proceed further
final Set<Object> allObjects_temp = new HashSet<>(allObjects); // --->a
allObjects.clear();
// Process these objects in a separate tasks parallely
executerService.submit(new Runnable() {
public void run() {
processData(allObjects_temp);// ---->b
}
});
}
}
executerService.shutdown();
}
private static Object getSomeObject() {
return "hello" + (Math.random() * 100000) + "" + (Math.random() * 100000);
}
protected static void processData(Set<Object> allObjects_temp) {
try {
Runtime rt = Runtime.getRuntime();
System.err.println(String.format("Free: %d Mb, Total: %d Mb, Max: %d Mb", rt.freeMemory() / 1000000,
rt.totalMemory() / 1000000, rt.maxMemory() / 1000000));
Thread.sleep(10);
System.out.println("done");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Result: The code is running forever. Also I checked that the memory is getting freed regularly and Jmap showed me that Object s is indeed being garbage collected. I still don't completely understand how?