Java Performance Tuning
Java(TM) - see bottom of page
Our valued sponsors who help make this site possible
JProfiler: Get rid of your performance problems and memory leaks!
Training online: Concurrency, Threading, GC, Advanced Java and more ...
Tips October 2025
|
JProfiler
|
|
Get rid of your performance problems and memory leaks!
|
|
JProfiler
|
|
Get rid of your performance problems and memory leaks!
|
|
|
Back to newsletter 299 contents
https://medium.com/itnext/essential-jvm-heap-settings-what-every-java-developer-should-know-b1e10f70ffd9?sk=24f9f45adabf009d9ccee90101f5519f
Essential JVM Heap Settings: What Every Java Developer Should Know (Page last updated August 2025, Added 2025-10-28, Author Abhinav Sonkar, Publisher ITNEXT). Tips:
- Use the JAVA_TOOL_OPTIONS environment variable to pass custom JVM flags to your Java application including into containers.
- Use -XX:+PrintCommandLineFlags to print all the JVM flags in use at startup.
- Use -XX:+PrintFlagsFinal for detailed information about all JVM flags including defaults.
- By default, the JVM uses 25% of available container memory for the heap. In containerized environments (like Kubernetes), increase this percentage to 60, 70, or 80% with -XX:MaxRAMPercentage=PERCENT.
- Specify the garbage collection algorithm rather than relay on defaults (G1 GC when memory is >= 2GB, but Serial GC for smaller heaps.
- The flag UseContainerSupport is enabled by default in Java 10 and later.
- Monitor garbage collection behaviour.
- In Kubernetes, set the memory "limit", not just the "request", to provide adequate JVM heap size.
- By default Metaspace has no size limit, so you consider setting MaxMetaspaceSize to avoid running out of memory.
- The Compressed Class Space is a sub-region of Metaspace that stores compressed object pointers. Its size is reported as 1 GB, but it is only allocated when needed, and the actual size is controlled by the MaxMetaspaceSize flag.
- The Reserved Code Cache stores JIT-compiled native code. It has a default size of 240 MB (from Java 10 onward). Monitor this region.
- In containers the heap size (if not set explicitly with -Xmx) is based on the container's memory limit. Adjust the -XX:MaxRAMPercentage to suit the available memory in the container.
https://www.youtube.com/watch?v=G_EHHFWNtwg
Java Perf & Scale: Mastering Techniques for Efficient Applications (Page last updated September 2025, Added 2025-10-28, Author Pratik Patel, Publisher NLJUG). Tips:
- Keep things simple & avoid premature optimization. The best performance often comes from simplicity, not clever tricks.
- Upgrading the Java version boosts performance. Simply moving from Java 8 or 11 to 21 gives a significant boost because OpenJDK is constantly improving.
- Monoliths are most efficient for pure performance. Microservices add JSON serialization, deserialization, and network overhead. Monoliths avoid this and are more CPU/memory efficient.
- Horizontal scaling is elastic, vertical scaling is limited.
- Architecture impacts performance and cost. Horizontal scaling (more instances) suits microservices but increases operating overhead.
- Use thread dumps in production instead of heavy profilers. Thread dumps taken in intervals (e.g., 0.5?2 seconds) can reveal bottlenecks without the overhead of profilers.
- Use JStack and comparison tools (e.g., jstack.review). Comparing sequential thread dumps helps identify blocking, deadlocks, or hotspots.
- Use JHiccup to detect JVM pauses and correlate with GC or system events. JHiccup measures pauses caused by GC, OS, or application events and is safe to run in production.
- Prefer primitives over wrapper types. Wrapper classes create more objects and GC pressure. Use primitives where possible for performance.
- Choose the right data structure.
- Micro-tuning: avoid String concatenation with += in loops; avoid unnecessary method calls inside loops; move loop-invariant code outside loops; avoid unnecessary synchronization.
- Cache compiled regex patterns.
- Preload caches at startup for max performance from launch.
- G1GC is a good default for most apps.
- Use GC logs & GC analysis tools to diagnose memory issues. Enable GC logging and analyze pause patterns before switching GC algorithms.
https://www.youtube.com/watch?v=IsqDuMhqou8
Performance testing how to do it right (Page last updated August 2025, Added 2025-10-28, Author James Livingston, Publisher JEurope). Tips:
- Define the purpose of the test - the question you are trying to answer: Does it scale to X requests/second? Can we reduce costs?
- The different types of tests: Load Test - test if the system can handle a specified load; Stress Test - find the breaking point of the system to understand its maximum capacity and what fails first; Microbenchmark - optimizing one small part of the code.
- Clearly isolate what you are testing to prevent noisy, irrelevant data from background load.
- Decide whether to use real external systems or to mock them out. Mocking provides isolation; using real systems finds end-to-end bottlenecks.
- Include detailed monitoring to tell you what the bottleneck is (e.g., CPU, lock contention, etc).
- Warm Up the JVM - JVMs need a warm-up period to reach peak performance.
- Use Realistic Loads. The test traffic must be representative of real-world or anticipated production volume. Unrepresentative loads tell you very little.
- Run Long Enough. A test should be long enough to allow the JVM to warm up and for the failure point to be sustained so you can zoom in and analyze the data.
- Ramp Up Slowly. Increase the load slowly to identify the exact threshold where the system begins to struggle (latency increases, requests wobble).
- Hold the Load. Maintain the target load for a long duration to ensure stability; many apps handle brief spikes but fail under sustained load.
- Select the correct request ijection model: keep sending requests regardless of system slowdown (like APIs) or slow down requests if the system is slow (like users).
- Do Not Use `System.currentTimeMillis()`. Use the Java Microbenchmark Harness (JMH). This correctly handles JVM warm-up, run-to-run variation, and compiler optimizations.
- Use Realistic Data. Simple, small data sets may artificially fit into CPU caches. Ensure your test data size reflects real production scenarios.
- Prevent Optimization. Use the Black Hole feature in JMH to consume the results of your tested function, which prevents the JVM from optimizing away the core logic of your benchmark.
- Identify the Bottleneck. Look for root causes like lock contention (threads fighting for resources), unexpected thread pool growth, or excessive I/O/logging.
- Decide when it's "Good Enough". After solving a bottleneck, a new one will appear (CPU, memory, database). Assess the business value: Is it worth spending a month to make the code 1% faster? Sometimes the cost of optimization outweighs the benefit.
- Re-run the same performance test after a fix to confirm the problem is solved and to identify the next bottleneck.
- Save and compare test results (screenshots, tables) to measure performance changes over time and ensure new features haven't created regressions.
Jack Shirazi
Back to newsletter 299 contents
Last Updated: 2025-10-27
Copyright © 2000-2025 Fasterj.com. All Rights Reserved.
All trademarks and registered trademarks appearing on JavaPerformanceTuning.com are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries. JavaPerformanceTuning.com is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
URL: http://www.JavaPerformanceTuning.com/news/newtips299.shtml
RSS Feed: http://www.JavaPerformanceTuning.com/newsletters.rss
Trouble with this page? Please contact us