5 ms·
The reason the Tomcat filled memory is that for the longest time Java would only run GCs if you were actually running out of memory. The assumption was, if ther
by origin_path 4y ago
The reason the Tomcat filled memory is that for the longest time Java would only run GCs if you were actually running out of memory. The assumption was, if there's RAM there doing nothing then why would you waste CPU and electricity on cleaning up the heap. If you needed that RAM for something else, OK, tell the JVM there's a cap on how much it can use. It'll then do enough GC work to use that much (ish).
The problem is, that wasn't really well advertised or understood, so people would see a Java program using lots of memory and assume that this is how much it really required. The elasticity wasn't apparent. These days the JVM can kick off background collections from time to time to reduce memory usage if the app is idle. However it still won't aggressively collect if the app is running because, again, if you haven't capped it then it figures that it's better to serve requests than do lots of "pointless" GC work.
- tgv 4y agoI think Go shows that that's a false dichotomy. Go can GC very quickly, almost without pauses, and the pauses are sub millisecond. That should be fast enough for almost all backends. Capping isn't great, although doable if you've got a steady workload.
- origin_path 4y agoThe argument for the Java behavior doesn't depend on how long pauses are. It's purely about efficiency. If your runtime is collecting then it's not spending that CPU time on your apps workload. If you're GCing to reduce your heap from 300M to 100M when you have 16GB free, your server is running slower than it needs to because GC work is more efficient when clearing a lot of garbage from the heap. Fundamentally with GC there's a throughput vs memory usage tradeoff. Go faces the same issue which is why GOGC exists: https://tip.golang.org/doc/gc-guide#GOGC https://tip.golang.org/doc/gc-guide#GOGC