Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Oct 2005 16:17:02 -0700
From:      Landon Fuller <landonf@threerings.net>
To:        freebsd-java@freebsd.org
Subject:   [PATCH] Sun Bug #4879883: Allocating direct buffers causes OutOfMemoryError
Message-ID:  <b9facca8733dd904d555aa7845420cbf@threerings.net>

next in thread | raw e-mail | index | archive | help

--Apple-Mail-11--496316617
Content-Type: multipart/mixed; boundary=Apple-Mail-10--496316627


--Apple-Mail-10--496316627
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed

 From http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4879883
A DESCRIPTION OF THE PROBLEM :
Allocating a direct byte buffer may give an OutOfMemoryError, even when 
plenty of memory is available.  Although not used in the test case 
below, in my application this occurs when reading a socket channel

----

We ran into this bug with jdk1.4.2; A simple reproduction case is 
included in the referenced Sun bug report.
This bug was fixed in 1.5.0 and 1.4.2_05.

I've back-ported Sun's changes from the 1.5.0 source. The patch (for 
1.4.2-p7) is attached below.

Please let me know if you have any questions,
-landonf


--Apple-Mail-10--496316627
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream; x-unix-mode=0644;
	name="reserveMemory-2.diff"
Content-Disposition: attachment;
	filename=reserveMemory-2.diff

Only in reserveMemory: cscope.out
diff -ru bsdjdk/j2se/src/share/classes/java/nio/Bits.java reserveMemory/j2se/src/share/classes/java/nio/Bits.java
--- j2se/src/share/classes/java/nio/Bits.java	Fri May 13 18:04:07 2005
+++ j2se/src/share/classes/java/nio/Bits.java	Mon Oct 24 11:41:10 2005
@@ -600,24 +600,39 @@
     // A user-settable upper limit on the maximum amount of allocatable
     // direct buffer memory.  This value may be changed during VM
     // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
-    private static long maxMemory = VM.maxDirectMemory();
-    private static long reservedMemory = 0;
+    private static volatile long maxMemory = VM.maxDirectMemory();
+    private static volatile long reservedMemory = 0;
     private static boolean memoryLimitSet = false;
 
     // These methods should be called whenever direct memory is allocated or
     // freed.  They allow the user to control the amount of direct memory
     // which a process may access.  All sizes are specified in bytes.
-    static synchronized void reserveMemory(long size) {
-	if (!memoryLimitSet && VM.isBooted()) {
-	    maxMemory = VM.maxDirectMemory();
-	    memoryLimitSet = true;
+    static void reserveMemory(long size) {
+
+	synchronized (Bits.class) {
+	    if (!memoryLimitSet && VM.isBooted()) {
+		maxMemory = VM.maxDirectMemory();
+		memoryLimitSet = true;
+	    }
+	    if (size <= maxMemory - reservedMemory) {
+		reservedMemory += size;
+		return;
+	    }
+	}
+
+	System.gc();
+	try {
+	    Thread.sleep(100);
+	} catch (InterruptedException x) {
+	    // Restore interrupt status
+	    Thread.currentThread().interrupt();
 	}
-	if (reservedMemory + size > maxMemory) {
-	    System.gc();
+	synchronized (Bits.class) {
 	    if (reservedMemory + size > maxMemory)
-		throw new OutOfMemoryError();
+		throw new OutOfMemoryError("Direct buffer memory");
+	    reservedMemory += size;
 	}
-	reservedMemory += size;
+
     }
 
     static synchronized void unreserveMemory(long size) {
diff -ru bsdjdk/j2se/src/share/classes/sun/misc/VM.java reserveMemory/j2se/src/share/classes/sun/misc/VM.java
--- j2se/src/share/classes/sun/misc/VM.java	Fri May 13 18:04:16 2005
+++ j2se/src/share/classes/sun/misc/VM.java	Tue Oct 25 15:04:28 2005
@@ -128,9 +128,14 @@
 	return booted;
     }
 
-    // A user-settable upper limit on the maximum amount of allocatable
-    // direct buffer memory.  This value may be changed during VM
-    // initialization if "java" is launched with "-XX:MaxDirectMemorySize=<size>".
+    // A user-settable upper limit on the maximum amount of allocatable direct
+    // buffer memory.  This value may be changed during VM initialization if
+    // "java" is launched with "-XX:MaxDirectMemorySize=<size>".
+    //
+    // The initial value of this field is arbitrary; during JRE initialization
+    // it will be reset to the value specified on the command line, if any,
+    // otherwise to Runtime.getRuntime.maxDirectMemory().
+    //
     private static long directMemory = 64 * 1024 * 1024;
 
     // If this method is invoked during VM initialization, it initializes the
@@ -140,6 +145,7 @@
     //
     // If this method is invoked after the VM is booted, it returns the
     // maximum amount of allocatable direct buffer memory.
+    //
     public static long maxDirectMemory() {
 	if (booted)
 	    return directMemory;
@@ -148,9 +154,16 @@
 	String s = (String)p.remove("sun.nio.MaxDirectMemorySize");
 	System.setProperties(p);
 
-	long l = (s != null ? Long.parseLong(s) : -1);
-	if (l > -1)
-	    directMemory = l;
+	if (s != null) {
+	    if (s.equals("-1")) {
+		// -XX:MaxDirectMemorySize not given, take default
+		directMemory = Runtime.getRuntime().maxMemory();
+	    } else {
+		long l = Long.parseLong(s);
+		if (l > -1)
+		    directMemory = l;
+	    }
+	}
 
 	return directMemory;
     }

--Apple-Mail-10--496316627--

--Apple-Mail-11--496316617
content-type: application/pgp-signature; x-mac-type=70674453;
	name=PGP.sig
content-description: This is a digitally signed message part
content-disposition: inline; filename=PGP.sig
content-transfer-encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (Darwin)

iD8DBQFDXrzulplZCE/15mMRAiW0AJ45tPPjwbB7mGpcMWTxbuRKvisM8QCdG0Em
BzchWS4vPPVMb12PRSYaZlw=
=2OaH
-----END PGP SIGNATURE-----

--Apple-Mail-11--496316617--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?b9facca8733dd904d555aa7845420cbf>