2

Questions are based on Oracle Hotspot JDK8.

When applicaton come across java.lang.OutOfMemory: Java heap space exception, I suppose, where are two possible reasons.

  1. Allocated JVM heap size reaches -Xmx specified size and GC system cann't squeeze out enough space.
  2. Allocated JVM heap doesn't reach -Xmx, but there are not enough physical memory for JVM heap to grow. Suppose -Xms < -Xmx.

I know 1 is a reason for JVM to throw out java.lang.OutOfMemory: Java heap space exception. Is 2 a reasonable one cause?

I find some articles mentioned java.lang.OutOfMemoryError: native memory exhausted, but they are all limited to IBM website. Is this expetion limited to IBM implemented JVM or it is a standard expetion in JVM Specification?


I did some experiments with code supplied by @Eugene in answer. As @Holger noted the result varies in different environments. I tested in on both CentOS x64 and Win7 x64, with Hotspot JDK8 x64. For simplicity swap and virtual memory are disabled.

I increase memory bound (-Xmx and -Xms) step by step.

I. -Xmx < available logic memory

  • On both CentOS and Windows it shows OutOfMemoryError: Java heap space

II. available logic memory < -Xmx < max physical memory

  • CentOS: The GC try to Full GC serveral times, with Allocation Failure, and process be killed by system, leaving a message Killed.
  • Windows: The GC try to Full GC serveral times, with Allocation Failure, and throw out OutOfMemoryError: Java heap space

III. -Xmx > max physical memory

  • CentOS: same as in II
  • Windows: same as in II

IV. -Xms > max physical memory

  • CentOS: JVM seems fail to start. Error message is like:

Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000e62a0000, 349569024, 0) failed; error='Cannot allocate memory' (errno=12)

  • Windows: JVM failed to start. Error message is like:

Error occurred during initialization of VM Could not reserve enough space for object heap


So, the same JVM behave differently in different OS.

  • On windows, the OS doesn't kill JVM. And JVM always throw out OutOfMemoryError: Java heap space when memory usage grow exceeds.
  • On Linux, the OS kill processes when there is not enough memory.
  • On both OS JVM failed to start when available memory doesn't satisfy JVM minimal requirement.
SuN
  • 421
  • 5
  • 11
  • Why don't you **try it** and see what happens? Set `-Xmx` to more than you have virtual space on your computer, then run a program that allocates space until it dies. --- *Hint:* Might be easier to run that in a Virtual Machine or in Docker, where you can better control how much memory the "machine" has. – Andreas Aug 20 '20 at 03:41
  • 1
    See https://stackoverflow.com/a/33927030/3448419 – apangin Aug 20 '20 at 07:00
  • 3
    It depends on the particular environment (including JVM implementation) whether a) `-Xmx` requires physical memory (rather then logical memory/swap space) and b) it allows to specify more maximum memory than the system can handle. There’s even that infamous Linux feature of overcommitting memory, i.e. it guarantees the availability of the memory in that the allocation request will never fail, but it just kills processes randomly when being out-of-memory. – Holger Aug 20 '20 at 07:37
  • @Holger from what I remember `-Xmx`, currently, will "commit" that much memory, that isn't resident yet. As to point number (2) : every single java person dealing with containers, especially kubernetes should be aware of this sudden death, especially since it does not support swap. Excellent comments. – Eugene Aug 20 '20 at 11:09
  • @Andreas I tried it seems it is get killed by system when in situation 2 – SuN Aug 21 '20 at 06:28

1 Answers1

1

First of all there are more reasons for a GC to fail with "out of memory" as the comment under your question explains.

Proving point number (2) is easy, just create some code that always allocates:

public static void main(String[] args) {
    test(1);
}

static void test(int x){
    List<byte[]> list = new ArrayList<>();
    while(x == 1){
        byte [] b =new byte[1 * 1024 * 1024];
        b[100] = 42;
        list.add(b);
    }

    System.out.println(list.hashCode());
}

And run this with -Xms1g -Xmx100g, on a system that has less then 100g of RAM. You can enable GC logs (I did with "-Xlog:heap*=debug" "-Xlog:gc*=debug" in java-9 flags for example) and see how hard GC is trying to cope with this constant allocation, ultimately failing.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • I tried it on CentOS with JDK8 (swap off). It is get killed by system when -Xmx is larger then pyhsical memory and JVM consumes all avaliable memory, only leaving a message **Killed**. So does it proves that I it show *OutOfMemoryError:Java heap space*, it could not be reason 2? – SuN Aug 21 '20 at 06:26
  • @SuN interesting. On my mac it dies with OOM. Did you run this in a container may be? – Eugene Aug 21 '20 at 11:39
  • No, I run the test in VirtualBox with CentOS and Windows 7 as Guest OS. More Details a listed in question description *Section II Experinment*. – SuN Aug 22 '20 at 03:32
  • @SuN exactly. You run in a virtualized container via VirtualBox. What you see is pretty much expected. – Eugene Aug 22 '20 at 12:19