Live data from Hacker News

Continuous delivery makes JVM JIT an anti-pattern

blog.astradot.com

11–20 of 37 posts

Re: Continuous delivery makes JVM JIT an anti-pattern

#11
This is about runtime binding vs static binding, not static objects or static members. There is still a "this", but the code that will run is known up front -- "ahead of time".

C++ went through this 25+ years ago: runtime binding, what in C++ is virtual functions, is a niche technique. Most C++ programs don't use it at all, or use it in only one or two spots. When it is the right thing, it makes the work convenient, but it really is just a dance with function pointers. In C++, templates do the heavy lifting.

Java never offered any other support for organizing programs, so inheritance and virtual functions have been your go-to for everything, no matter how bad the fit. In a static call there is only one bit of code to run, and it never changes over the life of the program. Just like almost everything, really, except here your runtime knows up front.

It was always a dumb choice to make member functions default to virtual semantics, when they almost always don't need it, and it just costs performance to no purpose. That is what comes out of treating language design as a marketing exercise: Java's designers really (and openly) cared less than nothing about object-oriented programming. They thought people really ought to be coding Lisp. Forcing runtime binding was a way to sneak in something a little bit lispy, and maybe get people used to production code running no faster than Lisp.

Re: Continuous delivery makes JVM JIT an anti-pattern

#12
Bad deployment system. You should do an A/B deployment and warm up the services/caches before the switch, so that the architecture handles the problem and not the programming language/VM.

At FastComments we run our E2E tests on the new instance to JIT the app. Before the Jit API calls can take 100ms, and after 10-30ms. Still, that is fast enough that most people wouldn't notice...

Also, the problem is not Java. Your application probably has way too many abstractions for a simple login page.

Re: Continuous delivery makes JVM JIT an anti-pattern

#13
post #7
post #5

Every serious Java based Web App I've ever worked on had a prewarm step or continuous probing setup for exactly these issues. It isn't unique to Java either - lots of languages have lazy library or dependency loading, or runtime caching of external files or the like that you want to do before you start serving requests.

Or a cache to be loaded. In related news, "Continuous delivery makes caching an anti-pattern".

Not really. You move cache off-heap in Java terms and it persists it between restarts. One Russian social network has about 60 gigabytes of stuff cached that way

Re: Continuous delivery makes JVM JIT an anti-pattern

#14
post #11

This is about runtime binding vs static binding, not static objects or static members. There is still a "this", but the code that will run is known up front -- "ahead of time". C++ went through this 25+ years ago: runtime binding, what in C++ is virtual functions, is a niche technique . Most C++ programs don't use it at all, or use it in only one or two spots. When it is the right thing, it makes the work convenient,…

Java is based on Objective-C, which is based on Smalltalk. In both of those all method calls are messages, which are even more abstract than virtual functions but a lot more useful.

Java simplified things for performance but ended up with a much weaker and less expressive system, and probably didn't go hard enough for static performance either. Still, it's less of a performance issue than the lack of value types.

Re: Continuous delivery makes JVM JIT an anti-pattern

#15
> Production Java apps also typically run with APM tracing agents that rely on runtime bytecode instrumentation. [...] It is easier to start afresh with modern compiled languages like Go and Rust.

I wonder how they instrument their Go and Rust programs. If they decide not to, maybe it's not that important for the Java version of the same code either.

Re: Continuous delivery makes JVM JIT an anti-pattern

#16
post #11

This is about runtime binding vs static binding, not static objects or static members. There is still a "this", but the code that will run is known up front -- "ahead of time". C++ went through this 25+ years ago: runtime binding, what in C++ is virtual functions, is a niche technique . Most C++ programs don't use it at all, or use it in only one or two spots. When it is the right thing, it makes the work convenient,…

> It was always a dumb choice to make member functions default to virtual semantics, when they almost always don't need it, and it just costs performance to no purpose.

If you actually don't need it (i. e., your hot methods are never overridden), then the JIT will trivially compile those "virtual" method calls as non-virtual ones. It has all the information it needs, since it knows what classes are loaded. It can invalidate its code if necessary, if you load more classes that do add overrides. So no, it does not cost performance at the call site. It does cause the compiler to do work, but nothing fancy.

Re: Continuous delivery makes JVM JIT an anti-pattern

#17
The article's "container lifespan" chart shows that 21% of containers live less than 10 seconds and 54% live Indeed, the original Sysdig report that the chart comes from makes this case:

https://sysdig.com/blog/sysdig-2019-container-usage-report/

"Many containers need to only live long enough to execute a function and then terminate when it’s complete. Seconds may seem short, but for some processes, it’s all that is required. We believe the increased use of Kubernetes Jobs that run finite tasks like batch jobs contributed to this growth. In fact, we expect short lifespans to increase, especially on serverless platforms that are well-suited to running short term tasks."

Re: Continuous delivery makes JVM JIT an anti-pattern

#18
post #12

Bad deployment system. You should do an A/B deployment and warm up the services/caches before the switch, so that the architecture handles the problem and not the programming language/VM. At FastComments we run our E2E tests on the new instance to JIT the app. Before the Jit API calls can take 100ms, and after 10-30ms. Still, that is fast enough that most people wouldn't notice... Also, the problem is not Java. Your…

But why all the complexity?

There is a huge DI framework full of reflection and proxy classes, then a complex JIT to make the framework performant and now finally a scheduled warmup/load test phase to make the JIT work.

It seems like the same or better performance could be archieved with far less complexity by using an AOT compiled language.

Re: Continuous delivery makes JVM JIT an anti-pattern

#19

> Production Java apps also typically run with APM tracing agents that rely on runtime bytecode instrumentation. [...] It is easier to start afresh with modern compiled languages like Go and Rust. I wonder how they instrument their Go and Rust programs. If they decide not to, maybe it's not that important for the Java version of the same code either.

No idea if this is done, but couldn't you in theory add the instrumentation before or during the compilation?

Something like a tool that runs as part of the build process and modifies the source code before it gets passed to the compiler.

Re: Continuous delivery makes JVM JIT an anti-pattern

#20
post #18
post #12

Bad deployment system. You should do an A/B deployment and warm up the services/caches before the switch, so that the architecture handles the problem and not the programming language/VM. At FastComments we run our E2E tests on the new instance to JIT the app. Before the Jit API calls can take 100ms, and after 10-30ms. Still, that is fast enough that most people wouldn't notice... Also, the problem is not Java. Your…

But why all the complexity? There is a huge DI framework full of reflection and proxy classes, then a complex JIT to make the framework performant and now finally a scheduled warmup/load test phase to make the JIT work. It seems like the same or better performance could be archieved with far less complexity by using an AOT compiled language.

Well I wouldn't use Spring, so that solves a lot of the problems... :)

I was never really a fan of DI.

Part of my point is your application should be fast enough before the JIT kicks in.

Ideally, you should also do performance testing. Incorporating that with your release go or no go is a great approach, IMO, if you do releases very often.

Post reply on HN