cloudfoundry / java-buildpack

Cloud Foundry buildpack for running Java applications
Apache License 2.0
433 stars 2.59k forks source link

Different JVM parameters for heap-calculation are kinda confusing #1052

Closed original-codematrix closed 4 months ago

original-codematrix commented 5 months ago

I'm facing the issue that IMO the memory calculation <= 512M RAM is not good at all due to even the application would run fine with ~200MB RAM (Heap). The current case was that the application had 650M RAM & the actual heap had only 48M. Which forced the application to die in seconds with some load.

One of my main issues is that the ReservedCodeCacheSize is way too big a set because it takes 240MB per default. Is there any specific reason to do that? When I set it down to the JVM default e.g. 48M it also works without problem.

The other fact is that when you normally work with JVM parameters you use e.g. MaxRAMPercentage or stuff like that. Is it planned that the calculator uses that flag in their calculation for the final heap/non-heap calculation? Because it would be much less painful to handle that case instead of the need to research the default Paketo values for specific JVM parameters.

dmikusa commented 5 months ago

The memory calculator will work, in that it'll generate settings, if you go below 1G of RAM, but as you can see it gets a little weird. You will probably need to step in and do some manual tune it. That is just a design consideration. It assumes at least 1G of RAM because this gives you a nicely configured JVM which will scale and perform very well (I believe a lot of the choices also mirror the JVM defaults).

When you go below 1G, you end up needing to make compromises where you might trade off a smaller RAM footprint for increased CPU usage/decreased throughput. It's hard for the memory calculator to make those decisions for you because they are application-dependent. Usually, this amounts to one or more of the following changes:

  1. Reducing the number of threads you will use (each thread by default needs 1M of thread stack). Maybe your app won't have a lot of concurrent connections, so you can reduce the default setting of 250 to something lower.

  2. Reducing the thread stack size. The default is 1M, which is also the JVM default, and often you can reduce that to 512 or 256K. So if you have 250 threads, by default that's 250M of RAM allocated to threads. If you reduce that to 256K thread stack size, then you drop to needing about 63M of RAM instead.

  3. Reducing the code cache size. As you found, it's a good chunk of memory. Again, this has trade-offs though. It's less memory the JVM has to store natively compiled code. Again, maybe your app is smaller and doesn't need a lot of space, but if your app does and you reduce the size, it will absolutely impact performance.

You can set these using the buildpack's configuration mechanism.

original-codematrix commented 5 months ago

Okay, as far I can understand that. I've also read the configuration stuff etc. before I even opened the issue 😄

I'll work with the given options above. But it may be good to document that a "little" bit as some information that < 1 GB RAM it may need adjustments for the calculation to work as good as someone would assume 😄

dmikusa commented 5 months ago

Yes, that's fair enough. That point has kind of been tribal knowledge.

I put some notes in the memory calculator readme on this subject. Let me know if you think that covers it: https://github.com/cloudfoundry/java-buildpack-memory-calculator/pull/52

original-codematrix commented 5 months ago

It would be great to have it yes, it covers that specific case. Thx! :)