开发者

Java: flushing memory out to disk

Let's say I have a Java application which does roughly the following:

  1. Initialize (takes a long time because this is complicated)
  2. Do some stuff quickly
  3. Wait idly for a long ti开发者_运维技巧me (your favorite mechanism here)
  4. Go to step 2.

Is there a way to encourage or force the JVM to flush its memory out to disk during long periods of idleness? (e.g. at the end of step 2, make some function call that effectively says "HEY JVM! I'm going to be going to sleep for a while.")

I don't mind using a big chunk of virtual memory, but physical memory is at a premium on the machine I'm using because there are many background processes.


The operating system should handle this, I'd think.

Otherwise, you could manually store your application to disk or database post-initialization, and do a quicker initialization from that data, maybe?


Instead of having your program sit idle and use up resources, why not schedule it with cron? Or better yet, since you're using Java, schedule it with Quartz? Do your best to cache elements of your lengthy initialization procedure so you don't have to pay a big penalty each time the scheduled task runs.


The very first thing you must make sure of, is that your objects are garbage collectable. But that's just the first step.

Secondly, the memory used by the JVM may not be returned to the OS at all.

For instance. Let's say you have 100mb of java objects, your VM size will be 100mb approx. After the garbage collection you may reduce the heap usage to 10mb, but the VM will stay in something around 100mb. This strategy is used to allow the VM to have available memory for new objects.

To have the application returning "physical" memory to the system you have to check if your VM supports such a thing.

There are additional VM options that may allow your app to return more memory to the OS:

-XX:MaxHeapFreeRatio=70 Maximum percentage of heap free after GC to avoid shrinking.

-XX:MinHeapFreeRatio=40 Minimum percentage of heap free after GC to avoid expansion.

In my own interpretation using those options the VM will shirk if it falls below 70%. But quite frankly I don't know if only the heap will shrink and be returned to the OS or only shrink inside the VM.

For a complete description on the hot memory management works see:

Description of HotSpot GCs: Memory Management in the Java HotSpot Virtual Machine White Paper: https://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf

And please, please. Give it a try and measure and let us know back here if that effectively reduces the memory consumption.


It's a bit of a hack to say the very least, but assuming you are on Win32 and if you are prepared to give up portability - write a small DLL that calls SetProcessWorkingSetSize and call into it using JNI. This allows you to suggest to the OS what the WS size should be. You can even specify -1, in which case the OS will attempt to page out as much as possible.


Assuming this is something like a server that's waiting for a request, could you do this?

  1. Make two classes, Server and Worker.
  2. Server only listens and launches Worker when required.
  3. If Worker has never been initialised, initialise it.
  4. After Worker has finished doing whatever it needed to do, serialize it, write it to disk, and set the Worker object to null.
  5. Wait for a request.
  6. When a request is received, read the serialized Worker object from disk and load it into memory.
  7. Perform Worker tasks, when done, serialize, write out and set Worker object to null.
  8. Rinse and repeat.

This means that the memory-intensive Worker object gets unloaded from memory (when the gc next runs, and you can encourage the gc to run by calling System.gc() after setting the Worker object to null), but since you saved it's state, you have the ability to reload it from disk and let it do it's work without going through initialization again. If it needs to run every "x" hours, you can put a java.util.Timer in the Server class instead of listening on a socket.

EDIT: There is also a JVM option -Xmx which sets the maximum size of the JVM's heap. This is probably not helpful in this case, but just thought I'd throw it in there.


Isn't this what page files are for? If your JVM is idle for any length of time and doesn't access it's memory pages. It'll very likely get paged and thus won't be using much actual RAM.

One thing you could do though... Most daemon programs have a startup phase (where they parse files and create data structures etc) and a running phase where they use the objects created at startup. If the JVM is allowed to it will start on the second phase without doing a garbage collection potentially causing the size of the process to grow and then stay that big for the lifetime of the process (since GC never/infrequently reduces the actual size of the process).

If you make sure that all memory allocated at each distinct phase of the programs life is GCable before the next phase starts then you can use the -Xmx setting to force down the maximum size of the process and cause your program to constantly GC between phases. I've done that before with some success.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜