preface
This week I sent out my resume as a Java backend development engineer. I had an interview with the interviewer Ali this week. During the interview, he asked about the Java garbage collection mechanism and algorithm. Today, he will talk about the Java garbage collection mechanism in detail based on the interviewer’s three questions.
Java object
Interviewer: How do I know if a Java object has been reclaimed
Me :(it’s hard for me)
Reference counting
Store a count RC for each object, counting RC++ when there are other references to it; When other references are disconnected, RC–; If there is RC=0, it (and all objects to which it points) is recycled.
Reachability analysis (root search algorithm)
Each object in memory is treated as a node, and some objects are defined as “GC Roots”. ** Starts with the object “GC Root” as the starting point and searches down the path known as the reference chain. ** If an object does not have any reference chain with the starting point, the specification is not available and needs to be reclaimed.
Object6, 7, 8 do not have any reference links to the start point, indicating that they are not available and need to be reclaimed.
Interviewer: Talk about the evolution of the JVM garbage collection algorithm
Me :(it’s hard for me)
The memory structure of the JVM (Java Virtual Machine)
Native Stacks | Local method stack |
---|---|
PC | A line number indicator that jumps to the next command to be executed |
Method area | Used to store class information, constants, static variables, etc. loaded by the VM |
Basic algorithms for garbage collection
Mark-clear algorithm
Definition: Set status bits (live/dead) for each object and record them, i.e. mark stage; Objects marked dead are cleaned, known as the sweep phase.
In simple terms, all marked objects are marked first, and all marked objects are collected after marking is complete.
Marking process:
-
Inefficient: The labeling and cleanup processes are inefficient
-
A large number of discrete memory fragments can be generated after The tag is cleared. Too much space fragmentation can cause large objects to fail to allocate enough contiguous memory and have to trigger GC early or even Stop The World
Mark-tidy
First mark all objects that need to be reclaimed
Move all surviving objects toward one end after marking is complete
Finally, the memory outside the end boundary is cleared directly
Disadvantages: time consumption is too long, affecting the program itself
Replication algorithm
This GC strategy differs from mark-collation in that instead of collating within the same region, live objects are copied entirely to another region.
Divide the available memory into two equally sized pieces based on capacity and use only one piece at a time.
When this block runs out of memory. First, mark all the objects that need to be recycled. After the mark is complete, all the marked objects are recycled, using only one piece at a time.
When a block of memory is used up, the surviving objects are copied to the other block and the used memory space is cleaned up.
flip(){
Fromspace, Tospace = Tospace, Fromspace
top_of_space = Tospace + space_size
scan = free = Tospace
for R in Roots {R = copy(R)}
while scan < free {
for P in Children(scan) {*P = copy(*P)}
scan = scan + size (scan)
}
}
copy(P) {
if forwarded(P){return forwarding_address(P)}
else {
addr = free
move(P,free)
free = free + size(P)
forwarding_address(P) = addr
return addr
}
}
Copy the code
Advantages:
-
Free compressed space
-
All object sizes are allocated very cheaply: just add idle Pointers to allocate
-
Only real-time data is processed (usually a small portion of the heap)
-
Fixed space overhead: free and scan Pointers
-
Comprehensive: recycled waste collected naturally
-
Easy to implement and reasonable and effective
Existing problems:
-
Efficiency problem: When the efficiency survival rate is high, the number of copies is high and the efficiency is low
-
Space issues: Memory has shrunk by half; Need extra space for distribution guarantee (old age)
Generation collection algorithm
The Java heap is divided into new generation, old generation, and permanent sections (renamed Metaspace after Java 8).
Different GC strategies are used for different regions
-
In the new generation, only a small part of objects can survive for a long time, so the replication algorithm is used
-
For older generations: Objects here have high survivability and use a “mark-clean” or “mark-clean” algorithm.
The JVM tuning
Interviewer: Tell me about a JVM tuning experience you had
Me :(it’s hard for me)
The problem
-Xms1000M
-Xmx1800M
-Xmn350M
-Xss300K
-XX:+DisableExplicitGC
-XX:SurvivorRatio=4
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
-XX:+CMSParallelRemarkEnabled
Copy the code
-Xms initializes heap memory
-Xmx indicates the maximum heap memory
-Xmn indicates the memory of the new generation
-xx :SurvivorRatio=4 indicates that the Eden of the new generation is 4/10, and S1 and S2 account for 3/10 respectively
Therefore, Eden’s memory size is 0.435010241024 bytes and 14010241024** bytes
The program
/ * * *@date: the 2020-03-22 09:48 * * /
public class JavaHeapTest {
public final static int OUTOFMEMORY = 500 * 1024 * 1024;
private String oom;
StringBuffer tempOOM = new StringBuffer();
public JavaHeapTest(int leng) {
int i = 0;
while (i < leng) {
i++;
try {
tempOOM.append("a");
} catch (OutOfMemoryError e) {
e.printStackTrace();
break; }}this.oom = tempOOM.toString();
}
public String getOom(a) {
return oom;
}
public static void main(String[] args) {
for(int i=0; i<50; i++) { JavaHeapTest javaHeapTest =newJavaHeapTest(OUTOFMEMORY); System.out.println(javaHeapTest.getOom().length()); }}}Copy the code
why
The young generation is divided into 1 Eden and 2 Survivor zones (one is from, the other is to). Newly created objects are typically assigned to the Eden zone, and if they survive the first GC, they are moved to the Survivor zone. Each time an object in a Survivor zone passes through a Minor GC, age +1, and when it reaches a certain age, it is moved to the tenured generation.
OUTOFMEMORY = 500 * 1024 * 1024, greater than Eden memory size. YoungGC is triggered frequently due to the small memory allocation in the new generation.
Initial heap memory is not consistent with maximum heap memory, and memory may be reallocated after each GC.
The solution
Increasing the size of the New generation
Set the initial heap memory to maximum memory
Change the SurvivorRatio from 4 to 8 so that as much rubbish as possible is recycled during the new generation
-Xmn350M -> -Xmn800M
-XX:SurvivorRatio=4 -> -XX:SurvivorRatio=8
-Xms1000m ->-Xms1800m
Copy the code
The effect
The number of YoungGC is significantly reduced
conclusion
About the whole process of the object from birth to recycling, see a great passage to share.
“I am an ordinary Java object. I was born in Eden. In Eden, I saw my little brother who looks like me.
“One day there were so many people in Eden that I was forced To go To the ‘From’ zone on Survivor. Ever since I went To the ‘From’ zone on Survivor, I’ve been floating around, sometimes in the ‘From’ zone on Survivor, sometimes in the ‘To’ zone on Survivor.
“It wasn’t until I was 18 years old that my father told me I was an adult and it was time to go out into the world. So I went to the old generation, the old generation, there are many people, and they are quite old, I know a lot of people here. In the old generation, I live for 20 years (plus one year per GC) and then get recycled.”
Reference links: blog.csdn.net/wuzhiwei549…