24

Why did the team at LMAX design the LMAX Disruptor in Java but all their design points to minimizing GC use? If one does not want to have GC run then why use a garbage collected language?

Their optimizations, the level of hardware knowledge and the thought they put are just awesome but why Java?

I'm not against Java or anything, but why a GC language? Why not use something like D or any other language without GC but allows efficient code? Is it that the team is most familiar with Java or does Java possess some unique advantage that I am not seeing?

Say they develop it using D with manual memory management, what would be the difference? They would have to think low level (which they already are), but they can squeeze the best performance out of the system as it's native.

14
  • 6
    I know very little about this project, but it seems it is some kind of framework that others can build upon. And if you manage to write that in Java (and allow others to code in Java and reap the benefits), then you'll have a MUCH larger "customer base" than if you'd have written it in D. Dec 23, 2013 at 14:11
  • 6
    @kadaj: it doesn't really matter if the consumer is public or internal: if you make it accessible in a widely-known language, it will be more useful, even for internal development. If you start your (hypothetical) argument with: "Assume that everyone knows D as well as they know Java, ...", then you're probably missing something. Dec 23, 2013 at 14:15
  • 6
    Some people like using hammers for all sorts of problems. Got a rough edge you want planing off, bash it with your hammer until its smooth. Got a screw you need driven in, bash it with a hammer until its in. Got a delicate ornament you need sanding down, bash it with a hammer and then blame the ornament for "sucking". C or C++ would have been a better choice than D, if only for the existing knowledge base. Not sure why you even brought up D as an example TBH.
    – gbjbaanb
    Dec 23, 2013 at 14:58
  • 2
    @gbjbaanb I mentioned D because it provides garbage collection (in cases where high level abstractions are necessary and fiddling with memory is too hard for the brain) but also allows manual memory management with C style malloc and free. D is sort of like Objective-C with ARC (no real GC) but better than that. But yeah, C/C++ would fit the bill.
    – user4626
    Dec 23, 2013 at 15:16
  • 4
    @kadaj I see you've been getting some flak here for bringing up D but I want to say I'm disappointed in the tone others are using and lay out why I think D is central to the question at hand. While D is indeed not widely used, D provides some high-level constructs that I might expect to find in say Java or C# but not in (at least old-style) C++. It still provides for mixing managed and unmanaged - which is just about the only language I know to do that! So D is not just a pet choice, but rather one that has goals coinciding with the original questions around GC.
    – J Trana
    Dec 24, 2013 at 6:46

6 Answers 6

19

Because there is a huge difference between optimizing the performance and turning off completely a safety

By reducing the number of GC, their framework is more responsive and can run (presumably) quicker. Now, optimizing for the garbage collector don't mean they don't ever do a garbage collection. It just mean they do it less often, and when they do it, it run really fast. Those kind of optimization include :

  1. Minimizing the number of object that move to a survivor space (i.e that survived at least one garbage collection) by using small throw-away objects. Object that moved to the survivor space are harder to collect and a garbage collection here sometime imply freezing the whole JVM.
  2. Don't allocate too many objects to begin with. This can backfire if you're not careful, as the young generation objects are super cheap to allocate and collect.
  3. Ensure that new object point to old one (and not the other way around) so that the young object are easy to collect, since there is no reference to them that will cause them to be kept

When you tune out the performance, you usually tune some very specific "hot spot" while ignoring code that don't run often. If you do that in Java, you can let the garbage collector still take care of those dark corner (since it won't make a lot of difference) while optimizing very carefully for area that run in a tight loop. So you can choose where you optimize and where you don't, and you can thus focus your effort where it matter.


Now, if you turn off completely garbage collection, then you can't choose. You must manually dispose of every object, ever. That method get called at most once per day? In Java, you can let it be, as its performance impact is negligible (it may be OK to let a full GC occur every month). In C++, you are still leaking resource, so you must take care even of that obscure method. So you must pay the price for resource management in every, single, part of your application, while in Java you can focus.


But it get worse.

What if you have a bug, let say in a dark corner of your application that is only accessed on Monday on a full moon? Java have strong safety guarantee. There is little to no "undefined behavior". If you use something wrong, an Exception is thrown, your program stop, and no data corruption occur. So you are pretty sure that nothing wrong can happen without you noticing.

But in something like D, you can have a bad pointer access, or a buffer overflow, and you can corrupt your memory, but your program won't know (you turned the safety off, remember?) and will keep running with its incorrect data, and do some pretty nasty things and corrupt your data, and you don't know, and as more corruption happen, your data get more and more wrong, and then suddenly it break, and it was in a life critical application, and some error happened in the computation of a rocket, and so it doesn't work, and the rocket explode, and someone die, and your company is in the front page of every newspaper and your boss point its finger to you saying "You are the engineer that suggested we used D to optimize performance, how come you didn't think of safety? ". And it is your fault. You killed those people with your foolish attempt at performance.


OK, ok, most of the time it is much less dramatic than that. But even a business critical application or just a GPS app or, let say, a government healthcare website can yield some pretty negative consequence if you have bugs. Using a language that either prevent them completely or fail-fast when they happen is usually a very good idea.

There is a cost to turning off a safety. Going native doesn't always make sense. Sometime it is much simpler and safer to just optimize a bit a safe language that to go all in for a language where you can shoot yourself in the foot big-time. Correctness and safety in a lot of case trump the few nano second you would have scrapped by eliminating the GC completely. Disruptor can be used in those situation, so I think LMAX-Exchange made the right call.

But what about D in particular? You do have a GC if you want for the dark corners, and the SafeD subset (that I didn't know of before the edit) remove undefined behavior (if you remember to use it!).

Well in that case its a simple question of maturity. The Java ecosystem is full of well-written tool and mature libraries (better for development). Much more developers know Java than D (better for maintenance). Going for a new and not-so popular language for something as critical as a financial application would not have been a good idea. With less-known language, if you have a problem, few can help you, and the libraries you find tend to have more bugs since they were exposed to less people.

So my last point still hold: if you want to avoid problems with dire consequences, stick with safe choices. At this point in the life of D, its customer are the little start-ups ready to take crazy risks. If a problem can cost millions, you are better staying further in the innovation bell curve.

5
  • 2
    The original post specifically calls out D. There is actually quite a big difference between C++ and D with regards to granularity of choice. Even if you do choose to go full-managed in the SafeD subset, I think you get quite a bit more control over certain aspects of collection and timing (enable/disable,collect,minimize). Check out Digital Mars' strategies for memory management!
    – J Trana
    Dec 24, 2013 at 7:27
  • 2
    lmax deliberately side step some of the safety Java provides
    – James
    Dec 24, 2013 at 16:33
  • This would be a great answer, except Java is not licenced for mission critical software. If you have anuclear reactor, it'll be written in C++ and not Java, which kinda throws the whole "safety" aspect out.
    – gbjbaanb
    Jun 27, 2016 at 7:42
  • @gbjbaanb , [citation needed]. The reliability standards/guidelines I have seen recommend first avoiding C/C++ in favor of other languages; and if getting into them, then using highly restricted versions of the languages (MISRA, etc). And once you accept restrictions, I don't see why you couldn't do the same with any other language. If you were thinking about Java Licence's mention of "not for nuclear facilities" in the RESTRICTIONS section, looks like that changed some time ago and now instead it just says something akin to "be careful, not our responsibility". Still, I assume the (...)
    – hmijail
    Sep 9, 2018 at 7:03
  • (...) original wording was just like gcc's and clang's licences: no guarantees for any specific purposes. So you wouldn't use them for something needing reliability, and instead you'd need to use some certified compiler, if not going all the way to some specific language for the job (Ada?).
    – hmijail
    Sep 9, 2018 at 7:06
4

It seems the reason it's written in Java is that they have Java expertise in-house and it was probably written (although it's still in active development) before C++ got its act together with C++0x/11.

Their code is really only Java by name, they use sun.misc.Unsafe quite a bit which kind of defeats the point of Java and the safety is supposedly gives. I have written a C++ port of the Disruptor and it outperforms the Java code they ship (I did not spend a lot of time tuning the JVM).

That said, the principles that the disruptor follows are not language specific, e.g. Don't expect low latency C++ code that allocs or frees from the heap.

1
  • Can you point to your implementation? I saw a couple of such reimplementations than claimed higher performance, but both cheated with simplifications: for example, hardwiring 1 producer + 1 consumer instead of being multi-producer/consumer capable like the original Disruptor. The author of the Disruptor himself mentioned in a Google Groups thread that the performance could be improved by hardwiring parameters in the Java version.
    – hmijail
    Sep 9, 2018 at 6:37
4

This question states an incorrect premise as fact, then makes an argument about that incorrect premise.

Lets dig in to this .. "all their design points to minimizing GC use" - simply isn't true. The innovation in the disruptor has little to do with GC. The disruptor performs because its design cleverly considers how modern computers work - something that's much less common than one might expect. See Cliff Click's talk http://www.azulsystems.com/events/javaone_2009/session/2009_J1_HardwareCrashCourse.pdf for a discussion.

Its well known that LMax are customers of Azul. I know firsthand that with Azul GCs are simply a nonissue - even with heaps of 175GB.

4
  • There's a grain of truth to this. They restart the VM every night to avoid a major collection. That's what Martin Fowler wrote, anyway and he's no dummy: "Like the rest of the system, the disruptors are bounced overnight. This bounce is mainly done to wipe memory so that there is less chance of an expensive garbage collection event during trading." martinfowler.com/articles/lmax.html
    – JimmyJames
    Jun 23, 2016 at 17:10
  • 2
    Not quite. We used to trigger a manual GC each night in a 5-minute trading gap, and tuned so that would be the only major GC in a day. That became redundant with Azul Zing. (Source: I worked at LMAX until recently) Jun 23, 2016 at 17:18
  • @TomJohnson Love getting the inside scoop. Are you saying that Martin Fowler's description is wrong? Is it possible the solution evolved over time?
    – JimmyJames
    Jun 23, 2016 at 17:22
  • 2
    I'm saying he wasn't precisely correct on some minor details. We never bounced our systems on a daily basis, but we did do some end of day cleanup. Jun 23, 2016 at 17:49
3

They would have to think low level

Above makes half of the answer you're looking for. You can find another half to complete the reasoning no farther than in LMAX blog:

While very efficient, it can lead to a number of errors as it is very easy to screw up...

As admitted by LMAX developers, code like that might be quite difficult to develop, understand and debug - even in Java. Going lower level further than where they are now will only exacerbate this problem, as pointed in Wikipedia article on low level programming languages:

A program written in a low-level language can be made to run very quickly, and with a very small memory footprint; an equivalent program in a high-level language will be more heavyweight. Low-level languages are simple, but are considered difficult to use, due to the numerous technical details which must be remembered.

By comparison, a high-level programming language isolates the execution semantics of a computer architecture from the specification of the program, which simplifies development...

3

If you use Java as a syntax language and avoid its JDK libraries it can be as fast as a compiled non-GC language. GC is not suitable for real-time systems, but it is possible to develop systems in Java that do not leave any garbage behind. As a result the GC never triggers.

We believe that the Java language and platform have many advantages over C/C++ and we have developed and benchmarked some ultra-low-latency Java components to prove it. We talk about the techniques to do so in this article: Java Development without GC.

2
  • 2
    There are garbage collectors suitable for real-time systems. The JVM's default collector may not be, but that doesn't mean GC in general is unsuitable for real time. But plain malloc/free isn't suitable for real time either since allocation time is unbounded due to fragmentation.
    – Doval
    Jun 12, 2014 at 16:58
  • 1
    We advocate the use of fast object pools for everything so no allocation happens after warming up.
    – rdalmeida
    Jun 12, 2014 at 17:01
1

LMAX is a High Performance Inter-Thread Messaging Library.

To be useful someone else has to write the code to get each thread to do useful work. Given that the code is most likely to be in Java or C# and then there are very few chooses of language that interface well with them.

Using C or C++ is not a good option unless you wish to limit your users to a single OS, as there is no threading model defined in them.

Java is the standard for a lot of software development these days, so unless you have a good reason otherwise, it tends to be the best choose. (When in Rome do as the Romans…)

Writing High Performance software in Java (or C#) is often done to prove a point…

5
  • 1
    The new C++11 standard supports multithreading...
    – Casey
    Dec 23, 2013 at 16:12
  • @Casey, and how many real world C++ compilers use it? And how much do these compilers cost. Maybe in 20 years times it will be useful, until then you can't depend on it.
    – Ian
    Dec 23, 2013 at 16:18
  • Disruptor uses sun.misc.Unsafe quite a bit which shows that you can't really write low latency code in Java without dipping your toe into C land
    – James
    Dec 24, 2013 at 16:24
  • 3
    Gcc supports C++ threads and it's free
    – James
    Dec 24, 2013 at 16:25
  • @Ian: 2 years later and all general used compilers support it ;). Even the ones which are free.
    – Rutix
    Dec 5, 2015 at 12:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.