Memory allocation and variable storage location

When the program is running, there are six places where data can be saved

1. Register:

This is the fastest save area because it's inside the processor. Registers are the top of the memory hierarchy and the fastest way for the system to obtain operational data. A limited number of registers are allocated by the compiler as needed. We have no control over this, and it is impossible to find any trace of its existence in our own programs.

2. Stack:

Store basic types of data and object references (variables), but the object itself is not in the stack, but in the heap.

Objects on the stack have a characteristic: the last object put on the stack is always the first to be taken out, this characteristic is often called a last-in-first-out (LIFO) queue . Some operations are defined in the stack. The two most important are PUSH and POP. The PUSH operation adds an element to the top of the stack. The POP operation, in contrast, removes an element from the top of the stack and decrements the size of the stack by one. In conventional RAM (random access memory) areas, direct support for processing is obtained through the stack pointer. Moving the stack pointer down creates new memory (PUSH), and moving it up releases that memory (POP). Speed ​​is second only to registers. When creating a program, the java compiler must know exactly the "length" and "how long" of all data held on the stack. This is because it has to generate the corresponding code to move the pointer up and down. This limitation undoubtedly affects the flexibility of the program, so although some java data is kept on the stack - especially the object handle, the java object is not placed in it.

3. Heap:

Store the data generated by new. is a general purpose memory pool, also in RAM area, in which java objects are kept. Unlike the stack: The most appealing thing about the "memory heap" or "heap" is that the compiler doesn't have to know how much storage space to allocate from the heap, or how long the stored data will stay on the heap. Therefore, you get more flexibility when saving data with the heap. When asked to create an object, simply use the new command to code the collision. When these codes are executed, the data is automatically saved in the heap. Of course, this flexibility comes at a price: it takes longer to allocate storage in the heap.

4. Static domain:

Stores the static members defined with static in the object. Static means in a fixed position. During program execution, statically stored data is waiting to be called at any time. A specific element of an object decorated with static is static. But java objects are never in static storage space.

5. Constant pool:

Store constants. Constant values ​​are placed inside program code and are safe. Because they never change, some constants require strict protection, so consider placing them in read-only memory (ROM)

6. Non-RAM storage: permanent storage space such as hard disk. If the data is completely independent of a program, it can exist when the program is not running and is outside the control of the program. Two of the prime examples are "Streaming Objects" and "Fixed Objects". For streaming objects, the object becomes a stream of bytes, usually sent to another machine, while for fixed objects, the object is kept on disk. They can maintain their state even if the program is terminated. A particularly useful technique for these types of data stores is that they can exist on other media, and even restore them to normal, RAM-based objects if needed.

 

Stack in java memory allocation (last in first out)

Some basic types of variable data and object reference variables defined in the function are allocated in the function's stack memory.

When the code defines a variable, java allocates memory space for the variable in the stack (the pointer down to the size of the PUSH stack top + 1), when the variable exits the scope, java will automatically release the memory space allocated for the variable (The pointer goes up the POP stack top size -1), the memory space can be used for other purposes immediately. The size and lifetime of the data in the stack can be determined. When there are no references to the data, the data disappears.

1. Each thread contains a stack area, in which only objects of basic data types and references to custom objects (not objects) are stored, and objects are placed in the heap.
2. The data (primitive types and object references) in each stack are private and cannot be accessed by other stacks.

3. The stack is divided into three parts: basic type variable area, execution environment context, operation instruction area (storing operation instructions)

 

heap in java memory allocation

Heap memory is used to store objects and arrays created by new. The memory allocated in the heap is managed by the Java virtual machine garbage collection mechanism.

After an array or object is generated in the heap, you can also define a special variable in the stack, so that the value of the variable in the stack is equal to the first address of the array or object in the heap, and the variable in the stack becomes an array. or a reference variable of an object. A reference variable is equivalent to a name for an array or object, and you can use the reference variable in the stack to access the array or object in the heap later in the program.

A reference variable is an ordinary variable whose definition is allocated on the stack. The reference variable is released after the program runs out of its scope. Arrays and objects themselves are allocated in the heap. Even if the program runs outside the code block where the statement that uses new to generate arrays or objects is located, the memory occupied by the arrays or objects themselves will not be released. Arrays and objects have no reference variables to point to it. When it becomes garbage, it cannot be used, but it still occupies memory space, waiting for the garbage collection mechanism to recycle at an indefinite time. The reason why java occupies more memory.

1. All objects are stored, and each object contains information of a corresponding class. The purpose of the class is to obtain operation instructions.

2. JVM has only one heap area (heap) shared by all threads. The heap does not store primitive types and object references, only the objects themselves.

Actually, variables in stack point to variables in heap memory, pointers in java.

 

heap and stack

Java's heap is a runtime data area from which class (objects) allocate space. These objects are created by instructions such as new, newarray, anewarray, and multianewarray, and they do not need to be explicitly freed by program code. The heap is responsible for garbage collection. Yes, the advantage of the heap is that the memory size can be dynamically allocated, and the lifetime does not have to be told to the compiler in advance, because it allocates memory dynamically at runtime, and Java's garbage collector will automatically collect these data that are no longer used. But The disadvantage is that the access speed is slower due to the dynamic allocation of memory at runtime.

  The advantage of the stack is that the access speed is faster than the heap, second only to the register, and the stack data can be shared. But the disadvantage is that the size and lifetime of the data stored in the stack must be deterministic, which lacks flexibility. The stack mainly stores some basic types of variable data (int, short, long, byte, float, double, boolean, char) and object handles (references).

       The stack has a very important particularity, that is, the data stored in the stack can be shared. Suppose we also define:

int a = 3;
int b = 3;

   The compiler first processes int a = 3; first it creates a reference to the variable a on the stack, then checks to see if there is a value of 3 on the stack, if not, it stores 3 in it, and then points a to 3. Then process int b = 3; after creating the reference variable of b, because there is already a value of 3 in the stack, it will point b directly to 3. In this way, a and b both point to 3 at the same time.

      At this time, if a=4 is set again; then the compiler will re-search whether there is a value of 4 in the stack, if not, it will store 4 and make a point to 4; if it already exists, directly point a to this address . Therefore, changes in the value of a will not affect the value of b.

  It should be noted that this sharing of data is different from this sharing of two object references pointing to one object at the same time, because in this case the modification of a does not affect b, it is done by the compiler, it is beneficial save space. An object reference variable modifies the internal state of the object, which affects another object reference variable.

For member variables and local variables: member variables are the variables defined outside the method and inside the class; local variables are the variables defined inside the method or statement block. Local variables must be initialized. 
Formal parameters are local variables, and the data of local variables exist in stack memory. Local variables in stack memory disappear as the method disappears. 
Member variables are stored in objects on the heap and are collected by the garbage collector. 

class BirthDate {  
         private int day;  
         private int month;  
         private int year;      
         public BirthDate(int d, int m, int y) {  
             day = d;   
             month = m;   
             year = y;  
         }  
         //省略get,set方法………  
     }  
 
     public class Test{  
         public static void main(String args[]){  
             int date = 9;  
             Test test = new Test();        
             test.change(date);   
             BirthDate d1= new BirthDate(7,7,1970);         
         }    
         public void change1(int i){  
             i = 1234;  
         }       
}  

For the above code, date is a local variable, i, d, m, y are all local variables, and day, month, and year are member variables. Let's analyze the changes when the code is executed: 
1. The main method starts to execute: int date = 9; 
date local variables, basic types, references and values ​​are stored on the stack. 
2. Test test = new Test(); 
test is an object reference, which is stored in the stack, and the object (new Test()) is stored in the heap. 
3. test.change(date); 
i is a local variable, and the reference and value are stored on the stack. When the method change is executed, i will disappear from the stack. 
4. BirthDate d1= new BirthDate(7,7,1970);  
d1 is an object reference, stored in the stack, the object (new BirthDate()) is stored in the heap, where d, m, y are local variables stored in the stack, and Their type is the base type, so their data is also stored on the stack. day, month, year are member variables, which are stored in the heap (in new BirthDate()). When the BirthDate constructor is executed, d, m, y will disappear from the stack.
5. After the main method is executed, the date variable, test, and d1 references will disappear from the stack, and new Test(), new BirthDate() will wait for garbage collection.

 

static domain

method area

1. Also known as the static area, like the heap, it is shared by all threads. The method area contains all class and static variables

2. The method area contains elements that are always unique in the entire program, such as class static variables.

There is no concept of static variables in java. If you don't believe that you define a static int i = 0 in the method, there are only static member variables in java. It is a property of the class. As for where he put it? Going deep into the jvm is translated into a static method area (it should also be called a domain). The architecture of the virtual machine: heap, method area, local method stack, pc register. The method area saves the template of a class, and the heap is where the instance of the class is placed. The stack is generally used for function computation. If you find any book on the bottom of the computer, you will know it. The data in the stack will not be stored after the function is executed. That's why local variables are the same every time. Even after adding one to it, it will still be the same when the function is executed next time.

 

constant pool

 The constant pool refers to some data that is determined at compile time and stored in the compiled .class file.

In addition to the constant values ​​(final) that contain various basic types (such as int, long, etc.) and object types (such as String and array) defined in the code, it also contains some symbolic references in text form, such as:

 Fully qualified names of classes and interfaces;

 field names and descriptors;

 Methods and names and descriptors.

If it has been created at compile time (defined directly with double quotes), it is stored in the constant pool, and if it is determined at runtime (new), it is stored in the heap. For strings whose equals are equal, there is always only one copy in the constant pool and multiple copies in the heap.

String is a special wrapper class data. Can use:

String str = new String("abc");
String str = "abc";

 There are two forms to create, the first is to use new() to create a new object, which will be stored in the heap. A new object is created each time it is called. The second is to first create an object reference variable str of the String class in the stack, and then go to the string constant pool to find out if there is "abc" in the string constant pool through symbolic reference. If not, store "abc" in the string constant. pool, and make str point to "abc", if there is already "abc", directly make str point to "abc".

  Use the equals() method to compare whether the values ​​in the class are equal; use == when testing whether the references of the two wrapper classes point to the same object. The following examples illustrate the above theory.

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true

 It can be seen that str1 and str2 point to the same object.

String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false

The way to use new is to generate different objects, one at a time.

 Therefore, using the second method to create multiple "abc" strings, there is actually only one object in the memory. This writing method is beneficial and saves memory space. At the same time, it can improve the running speed of the program to a certain extent, because the JVM will Automatically decide whether it is necessary to create a new object according to the actual situation of the data in the stack. For the code of String str = new String("abc");, new objects are created in the heap, regardless of whether their string values ​​are equal, whether it is necessary to create new objects, which increases the burden of the program.

On the other hand, be careful: when we define a class with a format such as String str = "abc";, we always assume that an object str of class String is created. Worry about the trap! The object may not have been created! Rather, it may just point to an object that has been created previously. Only through the new() method can a new object be created every time.

A few examples of String constant pool problems

String s0="kvill";
String s1="kvill";
String s2="kv" + "ill";
System.out.println( s0==s1 );
System.out.println( s0==s2 );

The result is

true

true

First know that Java will ensure that there is only one copy of a string constant

Because "kvill" in s0 and s1 in the example are both string constants, they are determined at compile time, so s0==s1 is true; and "kv" and "ill" are also string constants, When a string is formed by concatenating multiple string constants, it must be a string constant itself, so s2 is also parsed as a string constant at compile time, so s2 is also a "kvill" in the constant pool. Quote. So we get s0==s1==s2;

Example 2.

String s0="kvill";
String s1=new String("kvill");
String s2="kv" + new String("ill");
System.out.println( s0==s1 );
System.out.println( s0==s2 );
System.out.println( s1==s2 );

The result is:

  false

  false

  false

Strings created with new String() are not constants and cannot be determined at compile time, so strings created with new String() are not put into the constant pool, they have their own address space.

s0 is also the application of "kvill" in the constant pool. Because s1 cannot be determined at compile time, it is a reference to the new object "kvill" created at runtime. Because s2 has the second half of new String("ill"), it cannot be used in The compilation time is determined, so it is also an application of a newly created object "kvill"; if you understand these, you will know why this result is obtained.

Example 3


  String a = "a1";
  String b = "a" + 1;
  System.out.println((a == b)); //result = true 
  
  String a = "atrue";
  String b = "a" + "true";
  System.out.println((a == b)); //result = true 
  
  String a = "a3.4";
  String b = "a" + 3.4;
  System.out.println((a == b)); //result = true

For the "+" connection of the string constant, the JVM optimizes the "+" connection of the constant string to the value after the connection when the program is compiled. Take "a" + 1 for example, after the compiler optimizes The class is already a1. The value of its string constant is determined at compile time, so the final result of the above program is all true.

String a = "ab";
String bb = "b";
String b = "a" + bb;
System.out.println((a == b)); //result = false

For string references by JVM, since there are string references in the "+" connection of strings, and the value of the reference cannot be determined during program compilation, that is, "a" + bb cannot be optimized by the compiler. The program runs to dynamically allocate and assign the new address after the connection to b. So the result of the above program is also false.

Example 4

String a = "ab";
String bb = "b";
String b = "a" + bb;

System.out.println((a == b)); //result = false

Analysis: For string references by JVM, there are string references in the "+" connection of strings, and the value of the reference cannot be determined during program compilation, that is, "a" + bb cannot be optimized by the compiler, Only in the program runtime to dynamically allocate and assign the new address after the connection to b. So the result of the above program is also false.

Example 5

String a = "ab";
final String bb = "b";
String b = "a" + bb;

System.out.println((a == b)); //result = true

The only difference from Example 4 is that the bb string is final modified. For final modified variables, it is parsed at compile time as a local copy of the constant value stored in its own constant pool or embedded in its bytecode. in flow. So at this time "a" + bb and "a" + "b" have the same effect. So the result of the above program is true.

Example 6

String a = "ab";
final String bb = getBB();
String b = "a" + bb;

System.out.println((a == b)); //result = false

private static String getBB()
{  
    return "b";  
 }

For the JVM string reference bb, its value cannot be determined at compile time. Only after calling the method during program runtime, the return value of the method is dynamically linked with "a" and the address is assigned to b, so the result of the above program is false.

 

About String is immutable

From the above example, it can be concluded that:

  String  s  =  "a" + "b" + "c";

  is equivalent to String s = "abc";

  String  a  =  "a";

  String  b  =  "b";

  String  c  =  "c";

  String  s  =   a  +  b  +  c;

  This one is different, the end result is equal to:

StringBuffer temp = new StringBuffer();
temp.append(a).append(b).append(c);
String s = temp.toString();

 From the above analysis results, it is not difficult to infer that String uses the connection operator (+) to analyze the inefficiency of the reason, which looks like this code:

public class Test {
 
      public static void main(String args[]) {
 
        String s = null;
 
        for(int i = 0; i < 100; i++) {
 
            s += "a";
       }
    }
}

 Every time + is done, a StringBuilder object is generated, and then it is thrown away after append. The next time the loop is reached, a StringBuilder object is regenerated, and then the string is appended, and so on until the end. If we directly append StringBuilder objects, we can save N - 1 time to create and destroy objects. Therefore, for applications that need to connect strings in a loop, StringBuffer or StringBulider objects are generally used for append operations.

  Due to the immutable nature of the String class, there is a lot to say about this, as long as you know that an instance of String will not change once it is generated, for example: String str=”kv”+”ill”+” “+”ans” ; That is, there are 4 string constants, first "kv" and "ill" generate "kvill" in memory, then "kvill" is combined with " " to generate "kvill" in memory, and finally "kvill ans" is generated with "; and assign the address of this string to str, because String's "immutability" produces many temporary variables, which is why StringBuffer is recommended, because StringBuffer is changeable.

 

final usage and understanding in String

Java code

  final StringBuffer a = new StringBuffer("111");

  final StringBuffer b = new StringBuffer("222");

  a=b;//This sentence fails to compile

  final StringBuffer a = new StringBuffer("111");

  a.append("222");// Compilation passed

  It can be seen that final is only valid for the "value" (that is, the memory address) of the reference. It forces the reference to only point to the object originally pointed to, and changing its point will cause a compile-time error. As for changes to the object it points to, final is not responsible.

Summarize

 The stack is used to store some primitive data type local variable data and object references (String, arrays, objects, etc.) but does not store object content

 Objects created using the new keyword are stored in the heap.

 String is a special wrapper class, its reference is stored in the stack, and the content of the object must be determined according to the creation method (constant pool and heap). Some are already created at compile time and stored in the string constant pool, while Some are created at runtime. Use the new keyword and store them in the heap.

Reprinted from: https://www.cnblogs.com/protected/p/6419217.html

 

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325819399&siteId=291194637