13 ms·
ZGC – What's new in JDK 16
- geodel 6y agoSub milli sec GC pause is very impressive. Though one thing to me is not clear is that if it is true only for very large heaps or it will be great also for typical service/micro service heaps in range of 4-32 GB.
- perliden 6y agoZGC pause times will be the same regardless of heap size. ZGC currently supports heaps from 8MB to 16TB. So if you have 4-32GB heaps and want low latency, then ZGC is definitely something to try.
- eklavya 6y agoHey, is there any benchmark comparing throughput performance of ZGC vs G1 etc. How much hit (performance wise) would one take for getting this awesome pause time limit?
- kaba0 6y agoHere is a quite elaborate one, though it is not totally up-to-date: https://jet-start.sh/blog/2020/06/09/jdk-gc-benchmarks-part1 https://jet-start.sh/blog/2020/06/09/jdk-gc-benchmarks-part1
- geodel 6y agoAh, you are the author of article :). Thanks for replying! Does ZGC compromise on throughput compare to G1 to achieve low pause times?
- perliden 6y agoZGC in its current form trades a bit of throughput performance for better latency. This presentation provides some more details and some performance numbers (a link to the slides is also available there). https://malloc.se/blog/zgc-oracle-developer-live-2020 https://malloc.se/blog/zgc-oracle-developer-live-2020
- chrisseaton 6y agoI think the whole point is the pause time doesn't vary with the heap size.
- pradeepchhetri 6y agoIt works great even for large heap sizes. I moved my ES cluster (running with around 92G heap size) from G1GC to ZGC and saw huge improvements in GC. Best part about ZGC is you don't need to touch any GC parameter and it autotunes everything.
- JD557 6y ago>running with around 92G heap size I'm curious about this choice. The elasticsearch documentation recommends a maximum heap slightly below 32GB [1]. Is this not a problem anymore with G1GC/ZGC, or are you simply "biting the bullet" and using 92G of heap because you can't afford to scale horizontally? 1: https://www.elastic.co/guide/en/elasticsearch/reference/7.11/advanced-configuration.html#setting-jvm-heap-size https://www.elastic.co/guide/en/elasticsearch/reference/7.11...
- legerdemain 6y agoHeaps "slightly below 32GB" are usually because of the -XX:+UseCompressedOops option, which allows Java to address up to 32GB of memory with a smaller pointer. Between 32-35GB of heap, you're just paying off the savings you would have gotten with compressed object pointers, but if you keep cranking your heap further after that, you'll start getting benefits again.
- JanecekPetr 6y agoThis, exactly. One added issue is that ZGC does NOT support compressed oops at all.
- capableweb 6y ago> because you can't afford to scale horizontally? Doesn't have to be because of affordance but rather it's more efficient and cheaper to scale vertically first, both in monetary costs and in time/maintenance costs.
- vosper 6y ago
- bestinterest 6y agoThis might be an odd question but how often does garbage collection run and whats the usual time taken over a period of time? Say I'm doing a drawing/game app and creating a few hundred heap objects a second that need to get garbage collected. I have no idea on how often GC is run on a typical app and how much real time it takes over say an hour of an semi complex app running on average. It obviously depends on the app but I do not even have a number average cost of a GC language for some typical web app. I only know 'GC's are bad' because the 100s of HackerNews comments dismissing languages because they have a GC for some reason rather than hard examples of them eating up time.
- jankotek 6y agoIt really depends on application and complexity of object graph. Short lived object usually have low overhead. Long lived objects with huge heap may cause a problem. In past GC had bad reputation for increased and unpredictable latencies. In old JVMs GC would pause execution to traverse object graph. In general do not worry about GC, unless you run into performance issues. If performance is a problem, run continuous profiler such as Flight Recorded. It has very little overhead.
- _ph_ 6y agoAnd in most cases it isn't GC which is the problem, but the program doing too many heap allocations. Cutting heap allocations down improves the speed of most programs, with or without GC.
- dignan 6y agoGC is a memory management technique with tradeoffs like all the others. GC has many different implementations, with widely ranging properties. For example, the JVM itself currently supports at least 3 different GC implementations. There are also different types of GC's, so for example in a generational garbage collection system you'll typically see two or three generations of GCs, depending on the generation (how many GC cycles it has survived) of the objects it collects. The shortest GC's in those systems are usually a couple milliseconds, while the longest ones can be many seconds. GC isn't always a problem. If your application isn't latency sensitive, it's not a big deal. Though if you tune your network timeouts to be too low, even something that is not really latency sensitive can have trouble because of GC causing network connections to timeout. Even if it is a latency sensitive applicatoin, if GC "stop the world" pauses - pauses that stop program execution, are short it can be OK. One reason you'll see people say GCs are bad is for those latency sensitive applications. For example, I previously worked on distributed datastores where low latency responses were critical. If our 99th percentile response times jumped over say 250ms, that would result in customers calling our support line in massive numbers. These datastores ran on the JVM, where at the time G1GC was the state of the art low-latency GC. If the systems were overloaded or had badly tuned GC parameters, GC times could easily spike into the seconds range. Other considerations are GC throughput and CPU usage. GC systems can use a lot of CPU. That's often the tradeoff you'll see for these low-latency GC implementations. GC's also can put a cap on memory throughput. How much memory can the GC implementation examine with how much CPU usage with what amount of stop-the-world time tends to be the nature of the question.
- vlovich123 6y agoOne of the observations I've been making is that strategies like this of spreading the work around multiple threads almost seem to play with measurements more than necessarily improving the cost. So yes, the "stop the world phase" is shorter & cheaper. It's unclear the rest of the threads have more implicit overhead to support this concurrency (more book-keeping, participating implicitly in GC, etc). Supporting benchmarks of various workloads would be helpful to understand what tradeoffs were made.
- BenoitP 6y agoThere is an overhead: They use higher bits in the address space to indicate various stages in the object's collection (Shenandoah has a forwarding pointer IRCC). This means you may not activate the compressed pointers optimization.
- carry_bit 6y agoIn general if you the highest throughput you'll also get long pause times, since the techniques to reduce the max pause times depends on inserting barriers into the application code. Ignoring pause times is fine for batch processing, but not ideal for interactive systems.
- cogman10 6y agoGood observation. This is a fundamental principle of garbage collection. You can either have low latency or high throughput. You can't get both. Why is that? All optimizations that improve latency come at a cost. Generally, more book keeping, more checks, more frequent garbage collections. ZGC is one of those algorithms. It adds a new check every time you access memory to see if it needs to be relocated. That increases the size of objects but also the general runtime of the application. A similar thing happens with reference counting (which is on the extreme end of the latency/throughput tradeoff). Every time you give a shared pointer or release a shared pointer a check is performed to see if a final release needs to happen. On the flip side, a naive mark and sweep algorithm is trivially parallelizable. The number of times you check if memory is still in use is bound by when a collection happens. In an ideal state you increase heap size until you get the desired throughput. We get "violations" of some of these principles if we can take shortcuts or have assumptions about how memory is used and allocated. For example, the assumption that "most allocations are short lived" or the generational hypotheses leads to shorter pause times even when optimizing for throughput without a lot of extra cost. It's only costly when you've got an application that doesn't fit into that hypotheses (which is rare). Haskell has a somewhat unique garbage collector based on the fact that all data is immutable. They can take shortcuts because older references can't refer to newer references.
- BenoitP 6y ago> you can expect to see average GC pause times of around 0.05ms (50 µs) This is nuts (and very well below OS jittering)
- dan-robertson 6y agoWhat do you mean by OS jittering specifically?
- refulgentis 6y agohandwaving here, but broadly correct: modern OS' will try to arrange work/app wakeups so they happen at the same time - ex. if I schedule a 15 ms timer, and you schedule a 18 ms timer, maybe we both just get woken at 18. or 20. or the phone rang, so we had to kick up power to talk to the tower, lets grab email
- thu2111 6y agoE.g. some other thread that isn't yours getting timesliced onto your core. Or something in the OS interrupt handling code wiping out most of your CPU cache, etc. Bear in mind that by default most Linux distros will a timeslice of 10 milliseconds so your thread can easily skip that much time simply because it was some other thread's turn to run. JVM pauses with ZGC and even G1 most of the time (when set to the most aggressive settings) are now so low, that your pause times will be dominated by other factors.
- modeless 6y ago1 ms pause times are pretty good. That's finally getting close to the point where it may no longer be the biggest factor preventing adoption in applications like core game engine code. Although at 144 Hz it's still 14% of your frame time, so it's hardly negligible. Even if the GC is running on an otherwise idle core there are still other costs like power consumption and memory bandwidth. So you still want to minimize allocation to keep the GC workload down. For too long GC people were touting 10 ms pause times as "low" and not bothering to go further, but truly low pause times are possible. I'd love to see a new systems language that starts by designing for extremely low-pause GC, not manual allocation or a borrow checker. I think it would be possible to make something that you could use for real time work without having to compromise on memory safety and without having to pay the complexity tax Rust takes on for the borrow checker.
- The_rationalist 6y agoAlthough at 144 Hz it's still 14% of your frame time well if we believe their numbers, the worst case is 0.5ms so 6% of frame time for 144hz. Assuming their stated average pause time of 0.05ms then average pauses (and the GC isn't constantly pausing) take 0.6% of frametime, which is negligible. Though your concerns on throughput and resource usages stands. Well newer programming languages could leverage ZGC (and improve upon it) by targeting graalVM + it enable cross-language interop.
- modeless 6y agoIn my experience GC developers wildly underestimate their worst case, so I don't really believe that 0.5ms number. But more importantly, you should not use average pause time at all. At 144 Hz the 99th percentile frame time occurs more than once per second. If you want to avoid dropping frames you need to design for the worst case.
- kaba0 6y agoZGC used to target 10ms as worst-case latency, and they target 3-4ms now I believe.
- coldtea 6y agoQuestion: is the GC suitable for use with something like Idea or is it more for server workloads? Would it reduce UI GC-pauses lag accordingly?
- AnthonBerg 6y agoI confirm that ZGC works with IntelliJ IDEA, and it seems to me that it makes IDEA respond quite a bit faster. It's not hard to get IntelliJ IDEs to use ZGC by editing the VM properties file.
- perennus 6y agoI tried it last week actually with OpenJDK15+Windows. With JDK16, IntelliJ didn't boot. -XX:+UseZGC: Memory usage for my project dropped to a constant 600 megs. Using the IDE felt just as fast as the normal experience. -XX:+UseShenandoahGC, -Xmx4g. Shenandoah GC used a constant 4 gigs of ram. It was a slower user experience for me. In the end, I went back to the default settings, because the custom JDK changes the look and feel and I don't like it.
- coldtea 6y ago>-XX:+UseZGC: Memory usage for my project dropped to a constant 600 megs. Using the IDE felt just as fast as the normal experience. Shame, I hoped it would feel faster than the normal experience, with (even infrequent) user-felt GC pauses completely eliminated.
- olodus 6y agoReally impressive results. Sorry for my ignorance on the topic, but will this have any impact on other JVM languages or will this mostly only benefit Java itself? I realize even though I use JVM languages now and then I do not really know if they use their own GC implementation or make use of Java's. Does this differ between the languages maybe?
- buryat 6y agothis will work for any language that runs on top of JVM, that’s the beauty of the JVM, improvements benefit all its languages
- jfengel 6y agoThe JVM has its own garbage collector. Every language uses it. There may be tiny differences in the way code generators and optimizers work, which mean they may not get exactly the same properties out of equivalent code. For example, if they're generating a lot of objects behind the scenes, the GC improvements might help more, or less, or even do worse. But that's the kind of thing that's really dependent on the algorithm you've implemented. So mostly likely you get some benefit for free. If you don't, you'll need to benchmark to find out. The optimizers do a lot of work for you (and the JVM does a ton of language-independent optimization), but some things are up to experiment.
- bitmapbrother 6y ago>After reaching that initial 10ms goal, we re-aimed and set our target on something more ambitious. Namely that a GC pause should never be longer than 1ms. Starting with JDK 16, I’m happy to report that we’ve reached that goal too. ZGC now has O(1) pause times. In other words, they execute in constant time and do not increase with the heap, live-set, or root-set size (or anything else for that matter). Of course, we’re still at the mercy of the operating system scheduler to give GC threads CPU time. But as long as your system isn’t heavily over-provisioned, you can expect to see average GC pause times of around 0.05ms (50 µs) and max pause times of around 0.5ms (500 µs). Very impressive and well done. Should Azul be worried?
- novium 6y agoSince ZGC is in OpenJDK it should already be available in Zulu as well https://github.com/openjdk/jdk/tree/master/src/hotspot/share/gc/z https://github.com/openjdk/jdk/tree/master/src/hotspot/share...
- bondolo 6y agoAzul also has a separate closed-source Zing JVM which includes their C4 collector which could be described as an "uncle" of ZGC.
- Shadonototro 6y agoJava again show its superiority in the managed language world
- darksaints 6y agoIs there any chance this could make it's way into graal? Particularly native image? AOT compiled, PGO optimized, statically linked executables, with 0.5ms worst case GC pause times, sounds like the holy grail for me.
- aseipp 6y agoThere'd have to be a new implementation rewritten from scratch for native-image (the native-image GC is actually written in Java itself, while ZGC is written in C++), but I don't see any reason why it would be impossible. Note that Oracle does have intentions to commercialize similar features; there's already a low latency GC for native-image apps, but it's inspired by G1, not ZGC, I believe, and only available in Graal Enterprise Edition. So any such ultra-low-latency GC might be in a similar basket, unless it was implemented by an outside party or something. Or Oracle changes course on this. If you don't use native-image and can use a normal JDK to host your Graal app (by using Graal as the JVMCI compiler), then you might be able to use ZGC today with that setup, assuming support for ZGC read barriers has been implemented in Graal. EDIT: apparently not yet :( https://github.com/oracle/graal/issues/2149 https://github.com/oracle/graal/issues/2149