Please, do not say Java objects are allocated on the heap memory space up!

Java as an object-oriented, cross-platform language, its objects and memory has been more difficult knowledge, so that even a beginner Java, certainly more or less have some understanding of the JVM. It can be said with regard to knowledge of the JVM, is a basic knowledge of each Java developers must learn, is when the interview and tests of the knowledge points.

In the memory structure of the JVM, the more common of the two regions is the heap memory and stack memory (if not especially, are mentioned in this article refers to the virtual stack machine stack), about the difference between heap and stack, many developers also familiar, there are many books, or online articles about this are described:

1, the heap is the thread shared memory areas, thread stack is exclusive memory area.

2, the main storage heap object instance, the main storage reference stack all the basic data types, object.

However, the authors can responsibly tell you that, more than two conclusions are not entirely correct.

Before my article "Java heap memory is shared by the threads! Interviewer: Are you sure? "In, introduced on the heap memory is not completely threads share knowledge related article on the second topic to explore.

Object Memory Allocation

In the "Java Virtual Machine Specification", with respect to the reactor with this description:

In the Java virtual machine, the heap is available to run when the various threads of shared memory region, but also for the region all class instances and array objects allocate memory.

In the "Java heap memory is shared by the threads! Interviewer: Are you sure? "Articles, we also introduced a Java object at the time allocated on the heap, mainly in the Eden area, if you started TLAB then preferentially allocated on TLAB, a few cases may also be assigned directly in the old era , a fixed allocation rules are not one hundred percent, depending on the current use of what kind of garbage collector, as well as a virtual machine set up memory-related parameters.

But under normal circumstances it is to follow the following principles:

  • Objects priority allocation in Eden District
    • Priority in the allocation of Eden, Eden if there is not enough space, it will trigger a Monitor GC
  • Large objects directly into the old year
    • Java object requires a lot of contiguous memory space, when an object needs more memory than -XX: PretenureSizeThreshold parameter value, the object will be directly allocated memory in the old era.

However, while Virtual Machine Specification is with such a request, but each virtual machine manufacturers in the virtual machine, you may do some optimization for memory allocation object. This is one of the most typical is the JIT HotSpot virtual machine technology mature, so that the object allocated on the heap memory is not certain.

In fact, "in-depth understanding of the Java Virtual Machine", the author also made a similar point of view, because mature JIT technology makes "objects allocated on the heap memory" is not so absolute a. But the book did not begin introduced in the end what is JIT, nor introduce JIT optimizations in the end what has been done. So then we take a closer look:

JIT technology

We all know, by the javac Java source code can be compiled, converted into a java byte code, JVM by interpreting bytecode to translate it into machine instructions corresponding to read one by one, one by one interpretation translation. This is the traditional JVM interpreter (Interpreter) function. Clearly, the Java compiler interpreted through its execution speed much slower than direct execution is bound to the executable binary byte code. In order to solve this problem efficiency, the introduction of JIT (Just In Time, real-time compiler) technology.

With After JIT technology, Java programs or be interpreted by an interpreter, when the JVM find a method or block of code to run particularly frequent and they will think this is a "hot spot Code" (Hot Spot Code). JIT would then part of the "hot" translated into the machine code associated with the machine, and optimized, and then the cached translated machine code, the next use.

Hotspot detection

We said above, in order to trigger the JIT, you first need to identify hotspots code. The main focus of identification codes is to detect hot spots (Hot Spot Detection), HotSpot virtual machine uses mainly based on the focus detection counter

Focus detection counter (Counter Based Hot Spot Detection) based. Virtual machine using this method for each method, and even the number of executions to establish a code block counter, statistical methods, a method exceeds the threshold that it is the hot method, triggering JIT compiler.

Compiler optimization

After making a JIT hotspot detection codes to identify hot spots, in addition to its byte code cache, the code will make various optimizations. Optimization of these, the more important ones are: escape analysis, to eliminate the lock, the lock inflation, the associated method, a null check elimination, eliminate detection type, common subexpression elimination.

These optimization escape and analysis on the content of the article to introduce relevant.

Escape analysis

Escape analysis (Escape Analysis) is the Java virtual machine relatively cutting-edge optimization techniques. This is a function of the global data across flow analysis algorithm can effectively reduce the load and synchronization Java program memory heap allocation pressure. By escape analysis, Hotspot compiler can analyze the new use of a reference object to determine whether to assign the object to the heap.

The basic escape analysis is an analysis target dynamic scoping behavior: When an object is defined in the method, it may be referenced by external means, such as a call parameter passing to other places, the method referred to escape.

E.g:

public static String craeteStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb.toString();
}

sb is an internal variable method, the above code does not return directly to him, so that there will not be changed StringBuffer other methods, so that its internal scope just in the process. We can say that this variable does not escape to the external method.

With escape analysis, we can determine whether a method variables are likely to be accessed or changed by other threads, so based on this feature, JIT can do some optimization:

  • Synchronization is omitted
  • Scalar replacement
  • Allocated on the stack

About synchronization omitted, we can refer to my previous "in-depth understanding of multi-threaded (five) - Lock the Java virtual machine optimization technology" to eliminate the lock on the introduction of technology. This article analyzes the scalar distribution on the stack and replacement.

Scalar Alternatively, the stack distribution

We say, JIT after escape analysis, if an object is found not escape to the outside of their body method, it is possible to optimize it, and the biggest result of this optimization is possible to change the Java objects are allocated on the heap memory of this principle.

Target object to be allocated on the heap in fact there are many reasons, but one thing more crucial and this article, and that is because of heap memory is accessed on a shared thread, a thread is created out of this, other threads can access to.

So, Imagine, if we create a method within a body of an object, and the object did not escape to the outside, then the method, it is also necessary to take a certain object is assigned to the heap it?

In fact, it is not necessary, because the object will not be accessible to other threads, the life cycle is only within a method, will not be struggling to allocate memory on the heap, but also reduce the need for memory recovery.

Then, after the escape analysis has found that an object did not escape to the outside, then the put method can be optimized by any way, reduce the object allocated on the heap might do?

This is the stack on assignment. In HotSopt allocated and are not on the stack will be achieved, but is achieved by replacing the scalar.

So our focus on what is scalar replacement, how to allocate on the stack is achieved by replacing the scalar.

Scalar replacement

Scalar (the Scalar) refers to a data can no longer be broken down into smaller data. Java in the original data type is a scalar. In contrast, those data may also be called a decomposed amount of polymerization (Aggregate), Java objects is the amount of the polymerization, since he may be decomposed into other aggregate and scalar quantity.

In JIT stage, if after escape analysis, found that an object can not be accessed outside, then through JIT optimizations, this object will be broken down into a number of members of several variables contained therein instead. This process is replaced by a scalar.

public static void main(String[] args) {
   alloc();
}

private static void alloc() {
   Point point = new Point(1,2);
   System.out.println("point.x="+point.x+"; point.y="+point.y);
}
class Point{
    private int x;
    private int y;
}

In the above code, the object does not escape the point alloc method, and the object point can be broken down into scalar. So, JIT will not directly create a Point object, but direct use of two scalar int x, int y instead of a Point object.

private static void alloc() {
   int x = 1;
   int y = 2;
   System.out.println("point.x="+x+"; point.y="+y);
}

Can be seen, the amount of the polymerization Point after the escape analysis, and found that he did not escape, is replaced with the amount of polymerization into two.

By replacing the scalar, originally an object, has been replaced with more than one member variable. The original need memory allocated on the heap, is no longer required, can be completed for the member variable memory allocation method in the local stack.

Experiments show

Talk Is Cheap, Show Me The Code

No Data, No BB;

Next we come through a test, take a look at whether or not escape analysis can take effect, it really will be allocated on the stack occurred after the entry into force of allocated on the stack what good is it?

Let's look at the following code:

public static void main(String[] args) {
    long a1 = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        alloc();
    }
    // 查看执行时间
    long a2 = System.currentTimeMillis();
    System.out.println("cost " + (a2 - a1) + " ms");
    // 为了方便查看堆内存中对象个数,线程sleep
    try {
        Thread.sleep(100000);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
}

private static void alloc() {
    User user = new User();
}

static class User {

}

In fact, the code is very simple, is to use a for loop to create one million User objects in your code.

We define the User object in the alloc method, but did not quote him outside the method. In other words, the object does not escape to the outside alloc. After escape analysis JIT, it can optimize its memory allocation.

We specify the following JVM parameters and run:

-Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError 

Wherein -XX: -DoEscapeAnalysis escape analysis means closed.

After the program prints out the cost XX ms, before the end of the run the code, we use jmap command to view the number of User objects in the current heap memory are:

➜  ~ jmap -histo 2809

 num     #instances         #bytes  class name
----------------------------------------------
   1:           524       87282184  [I
   2:       1000000       16000000  StackAllocTest$User
   3:          6806        2093136  [B
   4:          8006        1320872  [C
   5:          4188         100512  java.lang.String
   6:           581          66304  java.lang.Class

We can see from the results jmap above, the heap CCP created one million StackAllocTest $ User instance.

In the case of closing the escape analysis (-XX: -DoEscapeAnalysis), although alloc User objects created in process method does not escape to the outside, but still be allocated in the heap memory. Also said that without the JIT compiler optimizations, there is no escape analysis techniques, under normal circumstances, it should be like this. That is, all objects are allocated heap memory.

Next, we open the escape analysis, implementation of the above come under the code.

-Xmx4G -Xms4G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError 

After the program prints out the cost XX ms, before the end of the run the code, we use jmap command to view the number of User objects in the current heap memory are:

➜  ~ jmap -histo 2859

 num     #instances         #bytes  class name
----------------------------------------------
   1:           524      101944280  [I
   2:          6806        2093136  [B
   3:         83619        1337904  StackAllocTest$User
   4:          8006        1320872  [C
   5:          4188         100512  java.lang.String
   6:           581          66304  java.lang.Class

From the above results it can be found in print, open the escape analysis after (-XX: + DoEscapeAnalysis), in heap memory is only more than 80,000 StackAllocTest $ User object. That after a JIT optimization, the number of objects in the heap memory allocation, from 1 million dropped 80,000.

After addition to the above method of authentication by jmap number of objects, the reader may attempt to transfer a small heap memory, and then execute the code above, according to the number of GC analysis can be found, the escape analysis open, during operation, the number of GC It will be significantly reduced. It is because a lot of the heap allocation is allocated on the stack optimized became so GC number has been significantly reduced.

Escape analysis is not mature

After the previous example, open the escape analysis, changing the number of objects from the 100 became 80,000, but not 0, description JIT optimization and all cases are not completely optimized.

Paper on escape analysis published in 1999, but only until JDK 1.6 implementation, and the technology to now also not very mature.

The fundamental reason for this is no guarantee that escape analysis of performance will be able to consume higher than his consumption. Even after escape analysis can be done scalar replacement, allocated on the stack, and lock eliminated. But their escape analysis also requires a complex set of analysis, it is also a relatively time-consuming process.

An extreme example is the analysis after the escape, an object is not found no escape. That escape this analysis process is wasted.

While the technology is not very mature, but he is also a time compiler technology is a very important means of optimization.

to sum up

Under normal circumstances, the object is to carry on the memory allocated on the heap, but as the compiler optimization technology matures, though virtual machine specification is required, but the specific implementation is quite different.

After the introduction of such HotSpot VM JIT optimization, you will escape analysis object, if a found object and a method does not escape to the outside, then it may alternatively be achieved by a scalar distribution on the stack, to avoid memory allocated on the heap.

Therefore, certain objects allocated on the heap memory, it is not right.

Finally, we leave a thinking questions, we had discussed before the TLAB, today introduced the allocation on the stack. I think these two optimization What are the similarities and differences do?

Guess you like

Origin www.cnblogs.com/hollischuang/p/12501950.html