Object memory allocation

The process of allocating memory for an object is complicated. It is commonly understood that the JVM will allocate the object directly to the heap when allocating memory for an object. In fact, the ACTUAL process is that the JVM will try to allocate the object on the stack first, and then allocate the object on the heap when the stack is unable to allocate memory.

On the stack

For on-stack allocation, it relieves heap memory stress as well as gc times. Not all objects attempt to be allocated on the stack, and the JVM performs escape analysis on them

Escape analysis

The process of escape analysis is to find escape objects and non-escape objects. The life cycle of a non-escape object is the same as that of the method itself, that is, it can be destroyed after the method is finished. Obviously, this kind of object is put on the stack with the stack frame, which can be destroyed faster, and can save the number of GC.

  public void func1(a){
        Run run=new Run();
        run.setName("wo");
        run.setWhyRun("her");
        // No escape, can try stack allocation
    }

    public Run func2(a){
        Run run=new Run();
        run.setName("wo");
        run.setWhyRun("her");
        // Escape, heap allocation
        return run;
    }
Copy the code
Scalar replacement

The stack memory space of each thread is very small compared to the heap. If there is not enough contiguous memory space in the stack, it is very difficult to allocate an object successfully. Therefore, even after passing the escape analysis, there will be a large number of objects trying to allocate on the stack failed, and finally the heap is allocated. So the general escape analysis needs to be used in conjunction with scalar substitution. Scalar substitutions break up the member variables of an object and store them separately, marking the object to which they belong. This allows stack allocation even if there is no contiguous memory space

Scalars are things that cannot be further decomposed, such as primitive data types in Java, and aggregate quantities are things that can be further decomposed, such as our custom classes.

EscapeAnalysis and Scalar Substitutions were enabled by default after JDK 1.7 Turn on EscapeAnalysis parameters (-xx :+DoEscapeAnalysis) Turn on Scalar substitutions parameters (-xx :+EliminateAllocations)

In pile distribution

Generally speaking, when an object is allocated in the heap, it is allocated to Eden. When Eden is full, minor GC is triggered to reclaim Eden, S0, and S1 memory space. How do you define a large object that goes directly into the old age when you allocate memory in the heap? Is a kind of object size is greater than the Eden area size, one is we have set the JVM parameter – XX: PretenureSizeThreshold can set the size of a large object, if the object is more than set size goes straight to the old age, not the young generation, This parameter is valid only for Serial and ParNew collectors. During a minor GC, the surviving objects are rotated back and forth between s0 and S1, The generational age of each stream is +1. When the generational age reaches 15, the object is put into the old age (the default is usually 15, slightly different for different garbage collectors) and the object is promoted to the old age threshold, You can set this parameter to -xx :MaxTenuringThreshold. If the surviving object’s generational age 1+ generational age 2 + generational age 3 + generational age N exceeds 50% of the memory size of s-region, the object with the generational age n or above will be directly placed in the old age. The JVM will determine if -xx :-HandlePromotionFailure (jdK1.8 default) is set if the Eden area storage object size before the MINOR GC exceeds the remaining memory size. If not set, go straight to full GC. If this parameter is set, it determines whether the remaining space of the current age is less than the average size of objects entering the age. If it is less than the average size of objects entering the age, full gc is performed; otherwise, MINOR GC is performed

Note that after JDK6 uptate 24 HandlePromotionFailure no longer works and the rule changes to Minor GC as long as the continuous space of the old generation is larger than the total size of the new generation object or the average size of the previous promotions, otherwise Full GC will be performed. That is, you do not need to set the default guarantee

Object memory reclamation

During GC, the JVM needs to determine which objects are garbage objects that can be collected.

Reference counting

Reference counting, as the name implies, records the number of references to each object, and if the number of references to an object is zero during gc, it is considered garbage that can be collected. Reference counting is simple and efficient, but garbage objects cannot be collected due to circular references. Therefore, most mainstream virtual machines use time-accessibility analysis algorithms

public class CountNumTest {

    public Object innerObj;

    public static void main(String[] args) {
        CountNumTest objA = new CountNumTest();
        CountNumTest objB = new CountNumTest();
        objA.innerObj = objB;
        objB.innerObj = objA;
        objA = null;
        objB = null; }}Copy the code
Accessibility analysis algorithm

Starting with GC Roots and searching down from these nodes, all referenced objects are marked as non-garbage and the rest as garbage. GC Roots: thread stack local variables, static variables, local method stack variables, etc.

Common reference types

Strong reference, soft reference, weak reference, virtual reference


import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

public class ReferenceTest {

    public static void main(String[] args) {
        / / strong reference
        String string = new String("strong");
        / / soft references
        SoftReference<String> stringSoftReference = new SoftReference<String>("stringSoftReference");
        / / weak references
        WeakReference<String> stringWeakReference = new WeakReference<String>("stringWeakReference"); }}Copy the code

Strong references and soft references are commonly used. Strong references: Generic objects that we declare will not be recycled as soft references during GC:

SoftReference<String> stringSoftReference = new SoftReference<String>("stringSoftReference");
Copy the code

Soft references are not reclaimed when there is enough heap memory, but are reclaimed when there is not enough memory to free up space. It can be used as a memory sensitive cache. Weak references Weak references are equivalent to no references, which are collected directly during GC and rarely used.

WeakReference<String> stringWeakReference = new WeakReference<String>("stringWeakReference");
Copy the code

Virtual references are also called phantom references, ghost references, the weakest type of reference, rarely used.

The Finalize () method finally determines the object survival

The first time an object is marked does not necessarily result in a death sentence for the garbage object. It will take at least a second marking before it is final. The second tag determines whether the object overrides the Finalize () method at the second tag. Objects have a chance to save themselves in finalize methods at this time. However, the running cost of Finalize () method is high and the uncertainty is great. Therefore, it is not recommended to use finalize() method because it cannot guarantee the call order of each object. This is good for understanding.

How do you tell if a class is useless

A class that is useless must satisfy all three of the following conditions

  1. All instance objects of the class have been reclaimed, that is, there are no instances of the class in the JVM heap
  2. The ClassLoader that loaded the class has been reclaimed
  3. The java.long.Class object of this Class is not referenced anywhere, and there is no way to generate the Class or access its methods through reflection anywhere.