JDK-8160638 : Solaris JVM unable to allocate more than 2GB of direct byte buffers when max heap is <= 2GB
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 8u91
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: solaris_11
  • CPU: x86
  • Submitted: 2016-06-29
  • Updated: 2021-02-26
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
SunOS tc-perf-026 5.11 11.2 i86pc i386 i86pc

A DESCRIPTION OF THE PROBLEM :
When I start the jvm with the following flags:

-XX:MaxDirectMemorySize=100g -Xmx2048m

I should be able to call java.nio.ByteBuffer.allocateDirect(32 * 1024 * 1024) 512 times to allocate a total of 8GB - but I get an OutOfMemoryError a bit before 2GB have been allocated.

This works fine on OS X, Windows and Linux but not on Solaris. But If I do start the solaris JVM with the following flags:

-XX:MaxDirectMemorySize=100g -Xmx2049m

then I'm able to allocate the 8GB of direct byte buffers.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I've included a simple test class (Buffers.java) that reproduces the problem. You just have to make sure:
 - that you're running it on a machine with enough free ram
 - that you add -XX:MaxDirectMemorySize=100g and -Xmx2g on the command line


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The above Buffers class should report that it successfully allocated the 8GB.
ACTUAL -
The above Buffers class catches OutOfMemoryError when a little below 2GB have been allocated.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.nio.*;
import java.util.*;

public class Buffers {
  // 32MB * 256 == 8GB
  private static final int BUFFER_SIZE = 32 * 1024 * 1024;
  private static final int BUFFER_COUNT = 256;

  public static void main(String[] args) throws Exception {
    long counter = 0L;
    try {
        List<ByteBuffer> buffers = new ArrayList<ByteBuffer>();
        for (int i=0 ; i<BUFFER_COUNT ; i++) {
                ByteBuffer b = ByteBuffer.allocateDirect(BUFFER_SIZE);
                buffers.add(b);
                counter += BUFFER_SIZE;
        }
    } catch(Throwable t) {
        t.printStackTrace();
    }
    System.out.println("allocated : " + (counter / 1024 / 1024 + " MB"));
  }

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I found two:

1) tell the JVM that its max heap size is over 2GB (ie: -Xmx2049m)
2) use libumem's mmap backend to start the JVM:
LD_PRELOAD=libumem.so UMEM_OPTIONS=backend=mmap java ...


Comments
Moving out of 12, for 13... [~dbuck] to determine next steps
04-12-2018

This is not on our list of current priorities. If there are additional specific customer requirements, we will consider reopening this issue. Closing as WNF.
04-01-2018

Code Review: http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2017-April/023069.html
01-06-2017

Without any command line flags then the maximum amount of memory that direct buffers can use is limited by Runtime.getRuntime().maxMemory(), which is effectively the maximum Java heap size. This is an implementation detail, which can be mitigated against by configured -XX:MaxDirectMemorySize. The output of testing is significant. In the case of a run on Solaris, without -XmxFFFF, the OOM is actually coming from Unsafe::allocateMemory, the malloc is failing, rather than from Bits::reserveMemory ( which enforces the MaxDirectMemorySize limit ). It appears that without an explicit -Xmx command line argument that the native heap is somehow being limited. My testing shows that the actual value passed to -Xmx is not actually that relevant.
31-05-2017

Max Direct Memory - 107374182400 java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:127) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at Buffers.main(Buffers.java:15) allocated : 2016 MB looks like a bug
15-02-2017

It doesn't look like issue to me, it depends on the what value sun.misc.VM.maxDirectMemory() returns. Forwarding for dev teams evaluation
30-06-2016

This issue observed on 8u92, on linux, JVM fails to allocate close to 4 GB (3360), when provided with -XX:MaxDirectMemorySize=100g it could allocate completly, -sh-4.1$ /opt/java/jdk1.8.0_92/bin/java Buffers java.lang.OutOfMemoryError: Direct buffer memory at java.nio.Bits.reserveMemory(Bits.java:693) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at Buffers.main(Buffers.java:13) allocated : 3360 MB -sh-4.1$ /opt/java/jdk1.8.0_92/bin/java -XX:MaxDirectMemorySize=100g -Xmx2048m Buffers allocated : 8192 MB //Slightly different behaviour on solaris machine -bash-3.2$ ./jdk1.8.0_92/bin/java Buffers java.lang.OutOfMemoryError: Direct buffer memory at java.nio.Bits.reserveMemory(Bits.java:693) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at Buffers.main(Buffers.java:14) allocated : 1792 MB -bash-3.2$ ./jdk1.8.0_92/bin/java -XX:MaxDirectMemorySize=100g -Xmx2048m Buffers java.lang.OutOfMemoryErrorin/java -XX:MaxDirectMemorySize=100g -Xmx2048m Buffers at sun.misc.Unsafe.allocateMemory(Native Method) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:127) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at Buffers.main(Buffers.java:14) allocated : 6208 MB
30-06-2016