15

I'm writing a high performance/low garbage application (microseconds matter) that has a networking component. One of the sore points that I've come across is the implementation of the built in Selector for Java NIO.

A few things that are problematic:

  • Lots of object creation. Pretty much every call to selectedKeys() creates a lot of objects. Iterators, boxing/unboxing, you name it. Not a problem with most other cases but the application I'm writing needs to create as little garbage as possible.
  • Layers upon layers of locking and synchronization. At the time the selectorImpls were built, a bunch of the Java lock primitives didn't exist. As a result it's clunky and not optimal. In my use case, there's only one thread calling select so the locking is in fact useless.

Extending or changing the selector implementation is a nonstarter. Most of the classes are final, with private and package-private members located in the sun.nio.ch.* package. Native methods also complicate things.

Are there any other more modern implementations of the selector that may be more performant?

The networking libraries I've examined just use the built in Java selector under the covers. Any help would be appreciated.

eak12913
  • 303
  • 4
  • 15
Laplie Anderson
  • 6,345
  • 4
  • 33
  • 37
  • Are you sure you don't wanna go with native selector? If microseconds matter on average execution of any java unit/class in C alternative is 1.5 - 2.3 times faster. – iantonuk May 16 '17 at 06:57
  • @bedbad Your source for that assertion? – user207421 May 16 '17 at 10:20
  • It's very well known. I have this information from blogs, C++ websites, Language Cons, books. MIT OWS Performance Engineering states it on the first lecture and, of course, through the personal experience with perfers. I can find an official link if I will feel it's necessary. – iantonuk May 16 '17 at 10:29
  • In fact you can calculate overhead that java VM creates by yourself tracing through the execution of compiled sources of java vm(written in C) – iantonuk May 16 '17 at 10:30
  • Just out of curiosity, when you have such high performance requirements, why do you code in Java? – Bastian Voigt May 16 '17 at 15:39
  • @bedbad . C usually is, but is not always faster than Java. C++ usually ties with Java. It depends on workload and what is being done. For example, object allocation is fastest in Java. Additionally, Hotspot JVMs are able to optimize code on the fly (based on how the code runs) vs only being able to optimize at compile time. Fact that you are more restricted in Java aids optimization. See http://stackoverflow.com/a/145122/14204 – Laplie Anderson May 16 '17 at 18:24
  • @BastianVoigt Easier to debug and test, faster iteration cycle, availability of opensource libraries, and the fact that in most cases, it matches the performance of a c++ implementation – Laplie Anderson May 16 '17 at 18:25
  • @bedbad , I might have to end up writing a new native selector myself (and interfacing using JNI) but I was hoping there was already one available in the opensouce community. There are so many networking libraries out there for java, it seems reasonable to assume. – Laplie Anderson May 16 '17 at 18:27
  • 1
    IMHO, if the garbage collection pause kills your use case, you should not use a language with a garbage collector. – Bastian Voigt May 17 '17 at 08:28
  • Agree with Bastian Voigt... "Easier to debug and test, faster iteration cycle, availability of opensource libraries, and the fact that in most cases, it matches the performance of a c++ implementation" are all useless, if the only (relevant) downside of Java is directly hindering your undertaking. Coralblocks seems promising though (if it does what the developers promise) and you can try to reimplement it yourself. The (unpredictability of the) garbage collector may break your neck anyways down the road. – Wolf May 17 '17 at 18:50
  • 1
    Do microseconds also matter for the networking component? If yes, then you should not use TCP/IP at all probably... Overall your question looks to me as if you would like to use some realtime OS or platform - since not only garbage collection can block a "normal" computer/OS/program for microseconds. – cyberbrain May 18 '17 at 11:15
  • 3
    SocketChannel and most of the Selectors were re-implemented in JDK 11 to eliminate the complicated locking need to support async close. In addition, Selector was updated with alternative select methods that invoke an action with the selected keys rather than adding them to the selected key set. That should add at least some of the concern about object allocation/GC. – Alan Bateman Sep 11 '19 at 09:47
  • @AlanBateman it still internally uses a for-each loop that uses iterator. Wouldnt it still cause object allocation? – experiment unit 1998X Mar 08 '23 at 05:53

3 Answers3

3

Maybe this lib satisfies your needs? Haven't used it myself, but looks promising. http://www.coralblocks.com/index.php/the-simplicity-of-coralreactor/

Imaskar
  • 2,773
  • 24
  • 35
  • I don't see any evidence there that this is or contains a reimplementation of `java.nio.channels.Selector.` – user207421 May 16 '17 at 10:10
  • Since the code isn't open, we cant see. But OP could ask developers or try to profile it to look himself. – Imaskar May 16 '17 at 10:32
  • 1
    " the native JDK selector produces a lot of garbage but we have fixed all these garbage leaks by implementing our own epoll selector"-, says one of developers (as he says) here: http://stackoverflow.com/a/23839791/78569 – Imaskar May 16 '17 at 10:52
  • @EJP - It probably doesn't. I think the OP would need to rewrite his application to use CoralBlocks. My understanding is that it is effectively Java syntax with a mostly non-Java class library. It claims to be *really fast* but the cost is license fees + lock-in. – Stephen C May 18 '17 at 12:19
3

Netty project has an implementation that uses Native epoll edge-triggered transport:

Since 4.0.16, Netty provides the native socket transport for Linux using JNI. This transport has higher performance and produces less garbage [...]

One possible drawback for you might be, it's available on Linux only.

On the positive side, Netty is an open-source project, may be the source code will give you a hint or two.

shpikachu
  • 147
  • 1
  • 3
  • 12
2

Regarding your first point about lots of object creation, you can ameliorate by using the select methods that were introduced in java11, the ones that accept an action Consumer as a parameter.

Before java11, every time you call a select() method, you have to call iterator() to access the events. This would create a new iterator object which would be subject to garbage collection. And this was unfortunately enshrined in the interface (abstract base class) itself.

The new methods iterate over the events themselves, applying your action, and reducing garbage.

Here's the javadoc for the new methods: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/channels/Selector.html#select(java.util.function.Consumer,long)

Joshua S
  • 301
  • 2
  • 6