Live data from Hacker News

Continuous delivery makes JVM JIT an anti-pattern

blog.astradot.com

21–30 of 37 posts

Re: Continuous delivery makes JVM JIT an anti-pattern

#21
post #10

Others have raised good points, but seriously something is wrong if you’re pushing updates that require restarts every hour. I get the idea of “continuous deployment”, but this is sounding like restart-per-commit. At that point I question how much qualification and validation is happening. No one say unit tests, they aren’t sufficient, and I’ve worked on multiple projects where the pre-commit test suite runs alone ca…

[deleted]

Re: Continuous delivery makes JVM JIT an anti-pattern

#22
post #6

> 74% of containers have lifespans ≤ 1 hour This sounds like a design flaw in the architecture. You don't tear down a house to replace a lightbulb.

I don't know if it's necessarily BAD architecture, but it certainly isn't typical in my experience. Most of my JVM deployments, even in containerized environments, have lifespans measured in AT LEAST hours, if not days. And the difference in performance between the first request and the requests occurring 30 seconds later is stark.

Re: Continuous delivery makes JVM JIT an anti-pattern

#23

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…

Good find. So sure, the lifespan is distributed down there, but surely there are some longer-lived services that benefit from JIT. I think most times you're spinning up a container + a JVM for what is effectively a function invocation you are maybe sad about paying the startup time for the JVM. Use Graal, or a different language?

Re: Continuous delivery makes JVM JIT an anti-pattern

#24
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 inv…

> 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.

But isn't that the thrust of this article? Of course the JIT can optimise a monomorphic call-site. The question is, in reality, what percentage of the time will it be optimised for your users?

Re: Continuous delivery makes JVM JIT an anti-pattern

#25
Kotlin methods are final by default unless marked open, and thus nonpolymorphic dispatch unless through an interface.

It sounds to me like the problem isn’t the VM it’s the insane amount of framework code you have to be initialized. This can be optimized with Java via class data sharing and snapshotting but if your code is all written in Kotlin and you toss Spring into the trash can In favor of say, Dagger or hand crafted DI, most of your problems would go away.

Besides, Kotlin/Native can compile and run without a VM.

See https://august.nagro.us/jvm-startup.html for examples of how to optimize startup without Prewarming JIT.

Re: Continuous delivery makes JVM JIT an anti-pattern

#26

Kotlin methods are final by default unless marked open, and thus nonpolymorphic dispatch unless through an interface. It sounds to me like the problem isn’t the VM it’s the insane amount of framework code you have to be initialized. This can be optimized with Java via class data sharing and snapshotting but if your code is all written in Kotlin and you toss Spring into the trash can In favor of say, Dagger or hand cr…

> Kotlin methods are final by default unless marked open, and thus nonpolymorphic dispatch unless through an interface.

This is a language construct and not enforced within the byte code. There have historically been reasons to allow final to be ignored, such as serialization. Instead the JIT will optimize and deoptimize based on runtime behavior, allowing it to cover cases where overriding is designed for but not done so in the actual runtime environment. There was a nice presentation on "truly final fields" at the 2018 language summit [1].

[1] https://www.youtube.com/watch?v=2HfnaXND7-M

Re: Continuous delivery makes JVM JIT an anti-pattern

#28
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.

> with far less complexity by using an AOT compiled language.

Or use reflection free frameworks like Micronaut or Quarkus and enjoy the same productivity. The culprit here is no java, the spring framework.

Re: Continuous delivery makes JVM JIT an anti-pattern

#29
post #26

Kotlin methods are final by default unless marked open, and thus nonpolymorphic dispatch unless through an interface. It sounds to me like the problem isn’t the VM it’s the insane amount of framework code you have to be initialized. This can be optimized with Java via class data sharing and snapshotting but if your code is all written in Kotlin and you toss Spring into the trash can In favor of say, Dagger or hand cr…

> Kotlin methods are final by default unless marked open, and thus nonpolymorphic dispatch unless through an interface. This is a language construct and not enforced within the byte code. There have historically been reasons to allow final to be ignored, such as serialization. Instead the JIT will optimize and deoptimize based on runtime behavior, allowing it to cover cases where overriding is designed for but not do…

It may not currently be enforced, but the compiler could enforce it, depending on assumptions, the same way we enforced it on the GWT compiler (of which I'm one of the engineers who worked on it)

With GWT, we had global information, so we could promote methods to static by class hierarchy analysis.

For a Kotlin class, even with dynamic loading, if the class is not marked 'open', final methods not implementing an interface, or private methods, can be converted into static methods.

e.g.

   class A(val x: Int) {
     fun print() = x
   }
can be transformed into

   class A(val x: Int) {
     fun print() = printStatic(x)
     companion object {
       fun printStatic(self: A) = self.x
     }
   }

And any call site with access to the original signature, e.g.

   val a = A()
   println(a.print())

could be rewritten safely as

   val a = A()
   println(A.printStatic(a))

Now, the current Kotlin compiler frontend or backend may not do any of these, but it could.

There's nothing in the compiler language itself that blocks such optimizations, especially if you're willing to limit reflection (as is the case with Kotlin MPP code), or admit a LTO pass.

Re: Continuous delivery makes JVM JIT an anti-pattern

#30
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.

> But why all the complexity?

Because it's probably a whole lot less work to add this new deployment mechanism than to completely change languages. Even for new projects there are tons of other things to factor in when picking a language; a crutch in one area can sometimes be the right call.

Post reply on HN