views:

184

answers:

9

Given this code, where we load a lot of data, write it to a file, and then run an exe..

void myMethod() {
    Map stuff = createMap(); //Consumes 250 MB memory
    File file = createFileInput(stuff); //Create input for exe
    runExectuable(file); //Run Windows exe
}

What is the best way to release the memory consumed by stuff prior to running the exe? We don't need this in memory any more as we have dumped the data to a file for input to the exe...

Is the best method to just set stuff = null prior to runExecutable(file)?

A: 

Alternatively:

 runExecutable(createFileInput(createMap()));

Be careful that the createFileInput method doesn't hold on to a reference to the Map instance!

Pointy
Does setting the map to null prior to running the exe accomplish the same thing?
Marcus
Yes it does - in both cases you are abandoning the last reference pointing to the huge map. This makes the map _eligible_ for GC. As Fazal pointed out, the VM need not initiate a GC cycle right then, but you can be guaranteed that before the VM throws an OOME it will make every attempt to reclaim all available memory. So, if holding this map is getting you OOMEs, nulling it out or structuring the code as show will help.
binil
A: 

Setting the map object to null is a good idea. You could even try to do System.gc() explicitly after setting map to null.

But remember that garbage collector would only work on tis own schedule and doing either of them does not guarantee garbage collector would run at that point itslef But if your Map is set to null you would not get OutOfMemory in normal cases as in worst case when jvm hits maximum heap size it would run the garbage collection for sure and therefore memory would get freed up.

Fazal
In a modern JVM, you almost certainly don't even need to set the Map to null. See http://stackoverflow.com/questions/2516723/freeing-java-memory-at-a-specific-point-in-time/2516846#2516846
noah
@noah: in any standards-compliant JVM, you most certainly need to set it to null before its contents become eligible for garbage collection.
Michael Borgwardt
The problem is that while the JVM may not run out of memory, it will also not free memory just because another process needs it.
Michael Borgwardt
@Michael, I wish you would stop asserting things that are not true. The standard says the opposite http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.6.1 "a compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner." After createFileInput(stuff), stuff is no longer used so a good JIT or compiler will set it to null.
noah
A: 

Setting stuff to null is surely necessary, but it wouldn't be sufficient without forcing garbage collection. I suppose the runExecutable function would wait before the execution finishes, so I'd run System.gc() in a different thread so the garbage collection happened while waiting.

jpalecek
The JVM will garbage collect if it needs the memory freed by stuff=null. You do not (and should not) call System.gc().
Steve Kuo
@Steve Kuo: I disagree - the biggest problem with this approach is that with applications that wait a considerable amount of time (like interactive applications), the GC will always happen in the "active" periods, which ought to be as short as possible, although it could have run during the idle phase. Calling System.gc() would be bad if it couldn't free much memory, but in this case - as we know 250 MB has just been freed - this is just not the case.
jpalecek
A: 
void myMethod() {
    runExectuable(createFile()); //Run Windows exe
}

File createFile() {
    Map stuff = createMap(); //Consumes 250 MB memory
    return createFileInput(stuff); //Create input for exe
}
binil
A: 

Since the Map stuff is declared locally inside of a method, so it should be eligible for garbage collection once the method exits.

Brian Bay
+2  A: 

Probably the best answer is: Do nothing.

The Java compiler is pretty smart. It can tell that stuff isn't needed anymore after createFileInput(stuff) and rewrites the code to ensure it is GCable. You can set it to null if you want to be 100% certain, but the compiler may have already done that for you. And setting it to null doesn't guarantee that it will be GC'd.

Try doing some profiling first, and I think you'll find that the memory is already freed. Naively examining your code to find places where you think there is a memory problem will rarely have good results. Get some data.

EDIT: Note that the compiler could be either javac or the JIT compiler. Both are very aware of things like this and make all sorts of optimizations that you wouldn't imagine. Bottom line: write clean code, then profile it and optimize from there.

EDIT2: For those interested in the sort of tricks the JVM plays with memory, I highyl recommend this blog (which explains this particular issue quite well): http://jeremymanson.blogspot.com/2010/02/garbage-collection-softreferences.html

noah
-1: This is nonsense. Neither the Java compiler nor the runtime will delete or initialize GC for Objects referred to by a variable that is in scope. If it did, it would severely violate the Java standard.
Michael Borgwardt
@noah: I know the .NET CLR is smart enough that it can collect objects as soon as it can prove they won't be used anymore, even if they are still in scope. (That's why it needs `GC.KeepAlive()`, for the rare cases where you want to defeat this behavior.) But this is the first time I've ever heard of the JVM doing the same thing. Do you have any reference for this behavior?
Daniel Pryden
@Michael, actually you're completely wrong about this. See http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.6.1 "Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner."
noah
A: 

@jpalecek How exactly do you think System.gc() will accomplish anything more than any other garbage collection invoked by the jvm when running low on memory()? Automatic garbage collection means just that.

deleted
Questions on other answers should be done in comments.
Robin
+1  A: 

If you are not comfortable with what @noah suggested (do nothing), or the code is being run in an environment which does not have a JIT or common runtime optimizations, a much cleaner alternative to the set to null and calling System.gc() would be to break up your code such that.

void myMethod() {
    File file = prepareFile(); //Prepare file for window exe
    runExectuable(file); //Run Windows exe
}

private File prepareFile() {
    Map stuff = createMap(); //Consumes 250 MB memory
    return createFileInput(stuff); //Create input for exe
}

This is cleaner code which will allow stuff to be eligible for collection once it drops out of scope. Explicit set to null and calling gc() are just hacks.

Robin
A: 

My first thought isn't to change the scope of references or force garbage collection, but can the memory requirement be reduced?

Can the functionality be refactored to allow the stuff to be generated as it is written to the file? Eg, can you reduce createMap and creatFile to something that calculates part of the map

while (mapFiller.hasMore()) {
    Map map = mapFiller.getNextPartialMap();
    mapWriter.writePartialMap(map);
}

Memory reduction would be my first approach, because even if you get the JVM to reclaim the memory, that doesn't mean it will necessarily release it back to the operating system.

Also see: JVM sending back memory to OS and Java VM - does the freed memory return to the OS?

Devon_C_Miller