Is there any way to force a JVM to use swap no matter how big the memory requirement is?

20,579

Solution 1

Apparently there is one way around the limits of Java heap. It is even used in a commercial product called BigMemory which basically allows you to have almost unlimited memory by transparently swapping out to OS swap and/or to disk if needed.

The idea is to use direct ByteBuffers to store your objects data. Because direct byte buffers' contents are stored in native process memory (as opposed to heap) you can rely on OS swap mechanism to swap memory out for you. I found this on this website (search for 'direct byte buffer' on the page).

Here is how you can implement it (java-pseudo-code'ish):

class NativeMemoryCache{
  private Map<Object, ByteBuffer> data = new HashMap<...>();

  public void put(Object key, Serializable object){
    byte[] bytes = serialize(object);
    //allocate native memory to store our object
    ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
    buf.put(bytes);
    buf.flip();
    data.put(key, buf);
  }

  public Object get(Object key){
    ByteBuffer buf = data.get(key).duplicate();
    byte[] bytes = new byte[buf.remaining()];
    buf.get(bytes);
    return deserialize(bytes);
  }

  private byte[] serialize(Object obj){ ... }
  private Object deserialize(byte[] bytes){ ... }
}

Hope you get the idea. You just need to implement the serialization (you can also compress your objects using zip. This will be effective if you have few big objects especially ones containing zippable data like strings).

Of course NativeMemoryCache object, data hash map and keys will be in heap, but that should not take much memory.

Solution 2

As pointed out by the other answers, you use the -Xmx switch to give more RAM to the JVM.

However, there's a limit on how high you can go. On a 32bit system, this will probably be 2GiB, maybe 3 or 4 GiB if the JVM supports it. For the Sun JVM, the limit is 1500MiB on 32bit Windows, according to Java -Xmx, Max memory on system .

For fundamental architectural reasons, a process cannot (without special techniques) get more than 4 GiB of memory (including any swap space it may use), that's why the limit on -Xmx values exists.

If you have tried the maximum possible value, and still get OOM Errors, then your only options are:

  • fix the application so it needs less RAM

or

  • move it to a 64bit OS, and increase -Xmx even further

Edit:

Note that the 4 GiB limit is a limitation of the CPU architecture, so it applies to any process, Java or not. So even native allocation tricks won't help you here. The only way around it is to use more than one process, but that would require a fundamental rewrite of the application, which would probably be as complicated as just fixing the app to use less RAM. So the two options above are your only (sensible) options.

Edit 2:

To address the new part of your question:

I was wondering if it is possible to make the JVM work like native processes.

This is a misunderstanding. The JVM does work like native process in this respect: The heap it uses is located in memory allocated from the OS by the JVM; to the OS this is just allocated memory, and the OS will swap it out like any other memory if it feels like it - there is nothing special about this.

The reason that the heap cannot grow indefinitely is not that it cannot be larger than physical RAM (it can, I have tried it at least on Linux/x86), but that each OS process (which the JVM is) cannot get more than 4GiB RAM. So on 32bit systems you can never have more than 4GiB heap. In practice, it may be much less because the heap memory must not be fragmented (see e.g. Java maximum memory on Windows XP ), but the 4GiB is a hard, unavoidable limit.

Solution 3

According to my experience JVM requests memory from OS that can allocate it either in RAM in swap. It depends on how much resources do you have. The memory you can allocate in java does not depend on your RAM but on command line option -Xmx you specify when you are running your JVM. If for example it is not enough memory in RAM JVM receives it from swap and (I believe) even does not know about that.

BTW IMHO you do not really need so much memory. I am agree with guys that said that. I'd suggest you to review your design.

Share:
20,579
mahonya
Author by

mahonya

Updated on August 02, 2022

Comments

  • mahonya
    mahonya almost 2 years

    Here is my situation: I have a task at hand that requires lots of memory. I do not have enough ram, and no matter what I tried (Jrockit with /3gb switch etc), I can't give JVM enough ram and the operation is terminated with an exception, telling me I need more heap space.

    Is there any way I can force the JVM to use the OS's swapping mechanism so that it won't run out of memory? This is Windows xp 32 bit

    It would take ages, but I would not care, I just need this operation to be completed.

    I've run out of options, and I have no control over any of the variables here..

    This is a required edit, since I am having the same response from pretty much everyone :) This is not my code. Someone has written a tool that reads an xml file into a repository. The tool uses EMF, and loads the whole model at once. All I can do is to feed it the XML file. In case of native code running under Windows or Linux etc, the OS provides memory to it, using virtual memory/swap space, and the app does not know about it. I was wondering if it is possible to do the same with the JVM. Under Windows 32 bit, -Xmx can go up to a certain amount, but that is not enough. Going out and buying new hardware is not an option for me for the moment. So I was wondering if it is possible to make the JVM work like native processes. Slow, but still working. Apparently that is not possible, and I am out of luck. I just need to know if I'm really out of options.