This author, Pierre, is a senior system architect with over more than 10 years of experience in Java EE, middleware and JVM technology. Based on his years of work experience, he has found that many performance problems are caused by inadequate Java heap capacity and tuning. Below he will share with you a very practical 5 Java heap optimization techniques.
1.JVM: Fear of things that are difficult to understand
Do not think, through the configuration, tuning, you can eliminate those you do not understand the problem. Some people think that Java programmers do not need to know the internal JVM memory management. There is no doubt that this view is clearly wrong, and if you want to broaden your knowledge and improve your ability to troubleshoot, you have to learn and learn about JVM memory management.
Java heap tuning and troubleshooting is a very challenging task for Java or Java EE novices. Some typical case scenarios are provided below:
The client environment faces a regular outofmemoryerror error and has a significant impact on the business.
What do your development teams usually do to solve this problem at such a high pressure?
- Use Google search engine to find similar problems and you will believe (or assume) you are facing the same problem.
- You'll catch jvm-xms and examples of the keywords that exist with OutOfMemoryError exceptions, and then hope to solve the client problem quickly with this case.
- Finally, you will use the same tuning method in your environment. Two days later, the problem still occurs (even worse or a little bit better) ...
What's wrong with it?
First, do you not have the root cause of your problem? The development environment is not properly understood in the deep surface (specifications, load conditions, etc.). Web search is a very good learning method and knowledge sharing tool, but you have to combine your own actual project, fundamentally analyze and solve.
There may be a lack of basic JVM and JVM memory management skills to prevent you from connecting all the dots.
The first tip of the day is to help you understand the basic JVM principles and their unique memory space. This knowledge is very important, it can help you to make effective tuning strategy, more correctly forecast the impact of the future, know ahead of time what needs to do tuning work. Here's a look at the JVM Reference guide:
JVM memory is divided into 3 memory spaces
- Java Heap: Applies to all JVM vendors and is often used to split Younggen (seedlings) and Oldgen (lifetime) space.
- PermGen (permanent): for Sun HotSpot VMS (PermGen space will be removed in Java7 or Java8 update)
- Native Heap (C-HEAP): Applies to all JVM vendors.
It is recommended to read the following articles, preferably by downloading and reading Sun's Java Memory Management white paper and OPENJDKS implementations.
- Sun HotSpot VMS
- IBM VMS
- Oracle JRockit VMS
- Sun (Oracle) –java Memory Management white Paper
- Openjdk–open-source Java Implementation
As you can see, JVM memory management is more complex than setting the maximum value using XMX. You need to look at each angle, including local and permgen requirements, and view physical memory availability (CPU core) from the host.
In the larger Java heap and smaller local heap races, 32-bit virtual machines can become quite tricky. Attempts to set up a large heap on a 32-bit VM such as 2.5gb+, depending on factors such as application occupancy and number of threads, will increase OutOfMemoryError this exception throws. The 64-bit JVM solves this problem, but physical resource availability and garbage collection costs are still limited (the cost is mainly concentrated on GC size collection). The maximum does not mean the best, so please do not assume that you can run 20 Java EE applications on a 16GB 64-bit virtual machine.
2. Data and Applications King: review static occupancy requirements
The application and related data will determine the Java heap footprint requirements. With static memory, you can "predict" the following memory requirements:
- Determine how many different applications will be deployed to a single, pre-planned JVM process, such as how many ear files, war files, jar files, and so on. The more applications deployed on a single JVM, the more demands are on the native heap.
- Determine how many classes need to be loaded at run time: including third-party APIs. The more ClassLoader and classes are loaded at run time, the higher the demand for hotspot VM PermGen space and internal JIT-related optimized objects.
- Determine data cache occupancy, such as applications loading internal cache data structures (and third-party APIs), such as data caches in databases, reading data from files, and so on. The more data caches are used, the higher the Java Heap oldgen space requirements.
- Determines the number of middleware threads allowed to be established. This is important because Java threads require enough native memory to throw outofmemoryerror exceptions.
The more applications deployed on the JVM process, the higher the requirement for local memory and PermGen space. The data cache is not serialized as a disk or database, it will require additional memory from the Oldgen space.
Trying to make a reasonable assessment of the static memory footprint, it is useful to set some starting point for the JVM capabilities before you actually test the data. For 32-bit JVMs, it is generally not recommended that a Java heap size exceed 2 GB (-xms2048m,-xmx2048m), and for Java EE applications and threads this will require sufficient memory and native heap PermGen.
This assessment is very important because too many applications deployed on a 32-bit JVM process can easily cause native heap exhaustion, especially in multi-threading environments.
For 64-bit JVMs, a 3GB or 4GB Java heap/JVM process is the recommended starting point.
3. Business flow Setup rules: Review dynamic memory footprint requirements
Business traffic typically determines dynamic memory consumption. By observing various monitoring tools you can find concurrent users with the JVM GC "Heartbeat" generated by the request, which is due to frequent creation and garbage collection of short or long term objects.
A typical 32-bit Jvm,java heap size set at 2 GB (using generational & concurrent collectors) typically allocates space and 1.5 GB of oldgen space for up to three MB Younggen.
Minimizing the frequency of significant GC collections is a key factor for optimal performance, so it is important to understand and assess how much memory is needed at peak times.
Again, the application type and data will determine the memory requirements. The type of application for the shopping cart (long-lived objects) involves both large and non-serialized session data, which typically requires a large Java heap and a lot of oldgen space. Stateless and XML processing (many short-lived objects) heavy applications require proper younggen space to minimize the frequency of major collections.
For example:
You have 5 ear applications (more than 2000 Java classes) to deploy (including middleware code)
- The local heap requirement is estimated to be 1GB (must be large enough to handle thread creation, and so on.) The PermGen space is approximately MB.
- Internal static cache approx. 500MB
- During peak times, total forecast traffic is 5,000 concurrent users
- Session data per user approx. 500K
- During peak periods, the total traffic session requirement is 2.5GB.
As you can see, in this case, the 32-bit JVM process is not sufficient. A typical solution is to perform traffic splitting on several JVM processes or physical hosts (assuming sufficient hardware and CPU cores are available).
Most of the time, business traffic will drive memory consumption. Unless you need a lot of data caching to achieve the right performance, a typical portal application site (media) is a heavy application requirement. Data cache too many times should be marked with a yellow flag, it is better to review some of the design elements earlier.
4. Tailoring
This article, you should do:
- Understand the basic JVM principles and memory space.
- Have in-depth knowledge of all applications and their characteristics (size, type, dynamic traffic, stateless objects vs stateful objects, internal memory caches, etc.).
- A good idea for predicting traffic (concurrent users) for each application is that if you need a 64-bit virtual memory, you'll start by setting which one.
If multiple JVM (middleware) processes are required.
Wait a minute, this isn't enough. Although the information above is critical, and the settings for the Java heap are "best guessed", the behavior of the application is simulated and the appropriate analysis, load, and performance tests are performed to validate the Java heap memory requirements.
Recommended Jprofiler tool for everyone, the best way to learn how to use a parser is to properly understand the memory footprint of your application. Another approach is to use the Eclipse mat tool to perform heap dump analysis based on an existing environment. Heap dumps are very powerful and allow you to view and understand the entire memory footprint of the Java heap, including ClassLoader-related data and what you must do in memory footprint analysis, especially memory leaks.
The Java parser and heap dump analysis tools allow you to understand and validate the application memory footprint, including detection and resolution of memory leaks. Load testing and performance testing are essential, and by simulating concurrent users to verify that an early assessment is correct, it exposes application bottlenecks and allows you to fine-tune them. Recommend a very easy to get started tool: Apache Jmeter.
At the end of this scenario, the application is very normal in the Java EE environment until a completely normal device startup fails, such as a hardware problem. What happened to the sudden decline in environmental performance and overall environmental degradation?
There are many reasons for the domino effect, but the lack of JVM tuning and the ability to handle failover (short-term additional load) is common. How do you anticipate a failover scenario if the JVM process is running in 80% + Oldgen space capacity and frequent garbage collection?
The load and performance tests in front of the simulation should simulate such scenarios, adjusting your tuning settings so that your Java heap has enough buffering to handle the extra load (additional objects) in the short term. This applies primarily to dynamic memory consumption, because failover means that some fixed concurrent users will be redirected to the available JVM processes (middleware instances).
5. Divide and conquer
The premise of this article is that you have completed dozens of load tests. The JVM is no longer leaking, and your application memory can not be reduced any further. You have tried several tuning strategies, such as using a 64-bit Java heap space above 10GB. Multiple GC policies, despite this, still not finding the right acceptable level of performance?
appropriate vertical and horizontal scaling, including the creation of JVM processes on each physical host and across multiple hosts to meet the overall throughput and capacity, compared to the current JVM specification. If you break the list of applications in several logical silos, their own JVM processes, threads, and tuning values, the fault tolerance of the IT environment will be even stronger.
The "Divide and conquer" strategy includes splitting application traffic to multiple JVM processes, with some split tips:
- Reduce the Java heap size (static and dynamic occupancy) for each JVM process
- Reduce JVM tuning complexity.
- Reduces GC churn and pauses each JVM process
- Increased redundancy and failover capabilities
- Align the latest cloud and it virtualization strategy
When you find that you've spent a lot of time tuning on 64-bit JVM processes, it's time to take a good look at your middleware and JVM deployment strategies and take advantage of vertical and horizontal scaling. The implementation of this strategy requires more hardware support, but in the long run it is very effective and beneficial. (Zhang Yue/compilation)
5 Tips for optimizing Java heap Size