Not envy mandarin duck not envy fairy, a line of code half a day. Original: Taste of Little Sister (wechat official ID: XjjDog), welcome to share, please reserve the source.
I have a deep affection for Java since CHILDHOOD, and have decades of Java experience. Back then, Java was Sun, and I had many years of Servlet experience, CURD experience, and now I have been reinvented to study the philosophy of life. That’s it. That’s it. This article is about Java troubleshooting.
To view the markdown brain map online, visit Mind.xjjdoc.cn
In order to keep the article flowing, I decided to finish it in one sitting. Because the relevant aspects of the training to do much, there is no need to write when reference materials, turn over the source code. By my fingers, this article has not taken an hour, but it is already a long one.
If it grows, cut it off. This article is the first part of memory troubleshooting, mainly about some principles. Why are we talking about principles? Is it necessary to understand the structure of the car to drive?
It really doesn’t compare.
Cars rarely break down. If something goes wrong, you pay towing companies, 4S shops. And you’re going to insure it every year.
On the other hand, problems occur in Java every two or three days. If someone fails to find a solution, money may not be able to solve the problem. Could you than? Take inventory, take inventory, and you’re on your own.
[toc]
1. What’s in memory
To troubleshoot memory problems, we need to look at what’s in memory. Let’s take a look at operating system memory partitioning and then JVM memory partitioning. Since the JVM itself runs on the operating system as a normal application, its behavior is also constrained by the operating system.
2. OS memory
Let’s start with the implementation of the operating system. Usually, if you write a C program and compile it, you’ll find that the memory address is fixed. In fact, when our application is compiled, these addresses are virtual addresses. It needs to go through a layer of translation before it can be mapped to real physical memory, and the MMU is the hardware responsible for address translation.
So how much free memory does our operating system have? It actually has two parts. Part of it is physical memory, which is the memory stick we plug in. The other part is virtual memory that uses disk emulation, commonly called swap partition in Linux. So, available memory = physical memory + virtual memory. If your system has swap enabled, the available memory is larger than the physical memory.
You can view the memory usage by running the top and free commands.
The top command can see the memory usage of each process. We usually pay attention to the RES column, which represents the actual memory usage of the process, and we usually monitor this number when setting up the monitoring system.
Let’s look at the demonstration of the free command again. Its presentation is actually a bit confusing, see the picture above for details. Usually, free is a small number, but that doesn’t mean the system has a little free memory. After Linux is started, the remaining memory is quickly used up by buffers and caches, which can be released when the reapplication space is insufficient. Available memory = Free + buffers + cached.
The memory usage of each area can be viewed using /proc/meminfo.
# cat /proc/meminfo
MemTotal: 3881692 kB
MemFree: 249248 kB
MemAvailable: 1510048 kB
Buffers: 92384 kB
Cached: 1340716 kB
40+ more ...
Copy the code
3.JVM memory partitioning
Next, let’s look at the JVM’s memory partitioning.
The largest area of memory in the JVM is the heap, where most of the objects we normally create are stored. The so-called garbage collection is also mainly aimed at this part.
Several JVM books have described that all areas of the JVM, except program counters, can overflow. We still agree with that conclusion here. The following is a brief introduction to these memory areas, because some of this knowledge is not useful for our memory cleanup.
- Heap: The data in the JVM heap, which is shared, is the largest area of memory
- Virtual machine stack: The Java virtual machine stack, which is thread-based and serves the execution of bytecode instructions
- Program counter: Line number indicator of bytecode executed by the current thread
- Meta space: The method area is here, not the heap
Local memory: Other memory usage
Analogously to the above image, we can return to the allocation of some commonly used objects. Don’t worry about on-stack allocation escape analysis, or the two-layer structure of stack frames and operands, these small details have too little impact on the sea of objects. The area of memory that we care about is really onlyWithin the heap memoryandOut of memoryTwo concepts.
The JVM memory has never been easier!
The following article explains each area in detail. I wanted to put it all together, but I didn’t think it would make it more important. So start reading the original.
Star article: Illustrated thousands of Sorrows, JVM Memory has never been Easier!
5. Why is there a memory problem
Statistics show that in our usual work, OOM/ML problems account for about 5%, and the average processing time reaches about 40 days. This shows that the investigation of this kind of problem is very difficult.
But it’s hard to say that when it comes to memory problems, engineers’ awareness of field protection is often inadequate, especially inadequate. All we know is the result of a memory overflow, but nothing is left. There’s no surveillance, no logs, not even a clear time frame. Such problems, god knows why.
6. Garbage collector
There are two modes of memory problems, one is memory overflow, the other is memory leak.
- Memory overflow OutOfMemoryError (OOM for short) is the most common case in the heap. It is difficult to check the memory outside the heap.
- A Memory Leak, or ML for short, is when allocated Memory is not released. Memory keeps growing, there is OOM risk; The collected items cannot be collected during GC. Or they can be recycled but fill up quickly, creating pressure.
Memory problems can also be significant, as shown in the following three scenarios.
- OOM Error occurs, application stops (most serious)
- Frequent GC, long GC time, high GC thread time slice occupation
- The service is slow, and the request response time becomes long
When it comes to this problem, we have to mention the garbage collector.
As soon as you look at the picture above, many of you will know that we are talking about G1 garbage collector, which is my recommendation. If you can, avoid using CMS. CMS will also be removed from Java14, and I really don’t want you to learn lessons that will become obsolete. The ZGC was awesome, but so new that almost no one dared to eat the crab, leaving the G1.
With three simple configuration parameters, the G1 achieves excellent performance in most cases, making engineers much happier. The three parameters are as follows:
- MaxGCPauseMillis Preset target, automatic adjustment.
- G1HeapRegionSize Size of the small heap area.
- InitiatingHeapOccupancyPercent heap memory ratio threshold, start concurrent tags.
If you’re still nervous and want to learn how the G1 works, we can also give you a quick tip. The G1 still has the concept of a younger generation, but its memory is discontinuous.
As shown in the figure, G1 divides memory into equal-sized areas called small heap areas, which are the smallest units of garbage collection. While previous garbage collectors were full generation collections, G1 is partial collection, so you can choose a reasonable number of small heap areas based on the configured minimum latency, and the collection process is much smarter.
7. GC Roots
As the figure shows, to determine what is garbage, there needs to be a way to find it. In fact, our last statement is not correct. In the JVM, garbage finding is the opposite of what we think it is: it finds the living objects, marks the living objects, and then reclaims the rest.
JVM garbage collection is concerned with not recycling objects that are not garbage, rather than cleaning up garbage objects.
To find out which ones are alive, you need to go back to the source. In the JVM, common GC Roots have static member variables, such as a static HashMap.
The other part is the contents of the virtual machine stack and the local method stack with which the thread is associated.
We’ve been talking about this for a long time, but there’s a name for this method of traceability: accessibility analysis. Reference counting is similar, but few collectors use this form because of the problem of ring dependence.
This does not mean that an object is alive as long as there is a Reference Chain with GC Roots. It also depends on the Reference level of the object.
- Strong citation: one of the most common and strongest beings, can only be wiped out if GC Roots are severed
- Soft reference: Only when memory is low, the system will reclaim soft reference objects
- Weak references: When the JVM does garbage collection, objects associated with weak references are reclaimed regardless of whether memory is sufficient
- Virtual references: Virtual references are mainly used to track the activity of objects being garbage collected
Normally, the object we use is a strong reference. Soft and weak references are widely used in some caching frameworks, and the importance of objects is relatively low.
8. Object promotion
Most garbage collectors are generational garbage collectors, as you can see from the description of G1 above.
As shown in the figure, it is a typical generation reclaim memory model. There are four ways objects can be promoted from the younger generation to the older generation.
- Regular promotionThe object is old enough. Let’s say you go from from to to 15 times and you don’t get recycled. The control parameters are
-XX:MaxTenuringThreshold
. This value defaults to 6 under CMS and 15 under G1 - Unable to allocate Survivor space, old age guarantee.
- Large objects are allocated directly in the old age
- Dynamic object age determination. For example, in G1, the TenuringThreshold changes with the distribution of objects in the heap
The optimization of the garbage collector is to ensure that as many objects are allocated in the young generation as possible, reducing the chances of objects being promoted to the old generation. This idea is much weaker in the G1, though.
End
Knowing what’s in the memory of the operating system, and knowing what’s in the memory of the JVM, allows us to calmly and indulgently troubleshoot and optimize every situation that goes wrong.
The article stopped abruptly here. In the next article, we will take a look at the specific process of troubleshooting Java memory problems with several practical cases.
Xjjdog is a public account that doesn’t allow programmers to get sidetracked. Focus on infrastructure and Linux. Ten years architecture, ten billion daily flow, and you discuss the world of high concurrency, give you a different taste. My personal wechat xjjdog0, welcome to add friends, further communication.