开发者

Freeing Java memory at a specific point in time

开发者 https://www.devze.com 2022-12-23 23:14 出处:网络
Given this code, where we load a lot of data, write it to a file, and then run an exe.. void myMethod() {

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 runExecutabl开发者_开发技巧e(file)?


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


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.


Alternatively:

 runExecutable(createFileInput(createMap()));

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


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.


void myMethod() {
    runExectuable(createFile()); //Run Windows exe
}

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


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


@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.


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?


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消