[PATCH]: Limit number of compiler instances in JavacServer to avoid OOM
Per Lidén
per.liden at oracle.com
Tue Nov 29 07:29:50 PST 2011
Hi all,
When I'm building on a 16 core machine the JavacServer will currently
OOM. On this machine the ./configure script will correctly figure out
that we should allow a maximum of 7 instances with the given 3G heap,
and sets JAVAC_SERVER_CORES accordingly. However, JavacServer later
fails to properly limit the number of compiler instances to
JAVAC_SERVER_CORES, instead allowing a new compiler instances to be
created for each concurrent connection it accepts (which will be equal
to NUM_CORES, i.e. 16 in this case), resulting in an OOM. The
JAVAC_SERVER_CORES value currently only dictates how many compilers can
run concurrently, not the number of instances it's allowed to create.
The patch fixes this by making sure Handler.grabHandle() never grows the
handler pool to more than JAVAC_SERVER_CORES (which propagates into
JavacServer as "poolsize").
Further, since the thread accepting incomming connections now risk
blocking for a handler to become available, we need to increase the
backlog on the server socket to avoid connection failures in the
clients. This number should probably be something like NUM_CORE (or we
should spawn a thread for each connection we accept), but right now I
just increased it to 128. Keeping it at default 0 will not work.
diff --git
a/src/share/classes/com/sun/tools/javacserver/JavacServer.java
b/src/share/classes/com/sun/tools/javacserver/JavacServer.java
--- a/src/share/classes/com/sun/tools/javacserver/JavacServer.java
+++ b/src/share/classes/com/sun/tools/javacserver/JavacServer.java
@@ -53,10 +53,12 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Stack;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Semaphore;
import java.util.logging.Logger;
import javax.tools.ForwardingJavaFileManager;
@@ -286,9 +288,10 @@
server_start = System.currentTimeMillis();
// Create a server socket on a random port that is bound to
the localhost/127.0.0.1 interface.
// I.e only local processes can connect to this port.
- serverSocket = new ServerSocket(0,0,InetAddress.getByName(null));
+ serverSocket = new ServerSocket(0,128,InetAddress.getByName(null));
int port = serverSocket.getLocalPort();
pool = Executors.newFixedThreadPool(poolSize);
+ Handler.setPoolSize(poolSize);
Random rnd = new Random();
my_cookie = rnd.nextLong();
si.setValues(port, my_cookie);
@@ -555,29 +558,44 @@
}
static class Handler implements Runnable {
- private static Handler[] handlers = new Handler[0];
- private static int available_handlers = 0;
+ private static Semaphore available;
+ private static Stack<Handler> handlers = new Stack<Handler>();
- public static synchronized Handler grabHandler() {
- if (available_handlers==0) {
- handlers = new Handler[handlers.length+1];
+ public static void setPoolSize(int poolsize) {
+ if (available != null) {
+ log("Internal Error: Handler pool size already set!");
+ System.exit(-1);
+ }
+ available = new Semaphore(poolsize, true);
+ }
+
+ public static Handler grabHandler() throws InterruptedException {
+ available.acquire();
+ return popHandler();
+ }
+
+ private static synchronized Handler popHandler() {
+ if (handlers.empty()) {
return new Handler();
}
- available_handlers--;
- Handler tmp = handlers[available_handlers];
- tmp.returned = false;
- handlers[available_handlers] = null;
- return tmp;
+
+ Handler h = handlers.pop();
+ h.returned = false;
+ return h;
}
- public static synchronized void returnHandler(Handler h) {
- if (h.returned == true) {
+ public static void returnHandler(Handler h) {
+ pushHandler(h);
+ available.release();
+ }
+
+ private static synchronized void pushHandler(Handler h) {
+ if (h.returned) {
log("Internal Error: Handler already
returned once!");
System.exit(-1);
}
h.returned = true;
- handlers[available_handlers] = h;
- available_handlers++;
+ handlers.push(h);
}
private boolean returned = false;
/Per
More information about the build-infra-dev
mailing list