Memory usage of EPollArraySelector

Patrick Bergamin patrick.bergamin at wedgenetworks.com
Thu Oct 22 20:50:40 UTC 2015


I'm having problems with memory usage of the current implementation
of EPollArraySelector in 1.8.0_60 for an existing proxy application.
We've been on java version 1.7.0_05 for a while now because the new
implementation of EPollArraySelector does not work well with the
design of this proxy application.

I did find the sun.nio.ch.maxUpdateArraySize property helped to
reduce memory usage a bit.  But as the proxy application runs
all the EPollArraySelector objects will slowly accumulate memory.

The current design of the proxy application is to have one Selector
handle the listen socket.  Once a connection is accepted, management
of the connection is handed off to another thread on another Selector.
Basically there is one Selector allocated per socket connection.
The Selectors are never closed they are reused when a new socket
connection is accepted.

The application was designed before this latest implementation of
EPollArraySelector.  Redesigning the application to decouple the
Selector from the socket connection would be a fair amount work.

We have machines that are capable of running this proxy application
with around 350,000 open connections.  Since it is a proxy there
are actually 700,000 open connections.  The file descriptor limit
is set high (5,000,000) to be able to handle all these open socket
connections.

Below I've included a patch to show what kinds of things I need
to do to bring the memory usage of EPollArraySelector down for
this proxy application.

Is there any interest in including a second epoll implementation
in openjdk that uses less memory or perhaps have more properties
to control the memory usage of the existing EPollArraySelector?

thanks,
Patrick Bergamin

--- EPollArrayWrapper.java    2015-07-30 06:27:02.000000000 -0600
+++ EPollArrayWrapper2.java    2015-09-28 15:31:41.712607415 -0600
@@ -29,6 +29,7 @@
  import java.security.AccessController;
  import java.util.BitSet;
  import java.util.HashMap;
+import java.util.HashSet;
  import java.util.Map;
  import sun.security.action.GetIntegerAction;

@@ -122,7 +123,7 @@

      // Used by release and updateRegistrations to track whether a file
      // descriptor is registered with epoll.
-    private final BitSet registered = new BitSet();
+    private final HashSet<Integer> registered = new HashSet<Integer>();


      EPollArrayWrapper() throws IOException {
@@ -187,7 +188,10 @@
              }
          } else {
              Integer key = Integer.valueOf(fd);
-            if (!isEventsHighKilled(key) || force) {
+            if (events == KILLED) {
+                eventsHigh.remove(key);
+            }
+            else if (!isEventsHighKilled(key) || force) {
                  eventsHigh.put(key, Byte.valueOf(events));
              }
          }
@@ -201,6 +205,9 @@
              return eventsLow[fd];
          } else {
              Byte result = eventsHigh.get(Integer.valueOf(fd));
+            if (result == null) {
+                return KILLED;
+            }
              // result should never be null
              return result.byteValue();
          }
@@ -235,7 +242,7 @@
          // force the initial update events to 0 as it may be KILLED by a
          // previous registration.
          synchronized (updateLock) {
-            assert !registered.get(fd);
+            assert !registered.contains(fd);
              setUpdateEvents(fd, (byte)0, true);
          }
      }
@@ -249,9 +256,9 @@
              setUpdateEvents(fd, KILLED, false);

              // remove from epoll
-            if (registered.get(fd)) {
+            if (registered.contains(fd)) {
                  epollCtl(epfd, EPOLL_CTL_DEL, fd, 0);
-                registered.clear(fd);
+                registered.remove(fd);
              }
          }
      }
@@ -286,7 +293,7 @@
              while (j < updateCount) {
                  int fd = updateDescriptors[j];
                  short events = getUpdateEvents(fd);
-                boolean isRegistered = registered.get(fd);
+                boolean isRegistered = registered.contains(fd);
                  int opcode = 0;

                  if (events != KILLED) {
@@ -298,9 +305,9 @@
                      if (opcode != 0) {
                          epollCtl(epfd, opcode, fd, events);
                          if (opcode == EPOLL_CTL_ADD) {
-                            registered.set(fd);
+                            registered.add(fd);
                          } else if (opcode == EPOLL_CTL_DEL) {
-                            registered.clear(fd);
+                            registered.remove(fd);
                          }
                      }
                  }



More information about the nio-dev mailing list