1. Memory Allocation in Java
JavaProgramDuring runtime, the memory structure can be divided into method, stack, heap, and local method stack (called by JNI in Java.
JVM allocates a stack (method stack) for each running thread. The stack stores the running state of the thread in frames. in Java, we call the currently running method the current method. When Java activates (executes) A method, it will press a frame into the stack, the frame in the stack represents the memory allocated by the JVM for this method at runtime. This frame is called the current frame, and the parameters of the method can be stored in the frame, intermediate results and local variables. When the current method is executed, the current frame will also be out of the stack, that is, the memory area is released. Method stacks only store basic type data and object references.
The basic data type is directly allocated in the stack space. The method format parameters are directly allocated in the stack space. After the method call is completed, the stack space is reclaimed. To reference the data type, you must use new to create a class variable that allocates an address space in the stack space and objects in the heap space. Method reference parameters: Allocate an address space in the stack space and point to the object area of the heap space. After the method is called, it is reclaimed from the stack space. When the local variable is new, space is allocated in the stack space and heap space. When the lifecycle of the local variable ends, the stack space is immediately recycled, and the heap space area is waiting for GC to be recycled. The literal parameter passed in when the method is called. It is first allocated in the stack space, and then allocated from the stack space after the method is called. String constants are allocated in the data area, and this is allocated in the heap space. The array not only allocates the array name in the stack space, but also allocates the actual size of the array in the heap space!
This figure is incorrect. frames do not include heap memory. The method stack for storing frames is private to the thread and cannot be accessed by other threads, the memory for storing objects and arrays is shared by multiple threads, and there is only one copy of the entire JVM.
At my current level, I can only draw to this level. I still have many questions to understand.
A more intuitive diagram of memory allocation will be displayed during debugging.
Each thread has its own stack, and the method is pushed into the stack in the form of frames.
Where are global constants stored in global variables of a class?
This information is stored in a location called the method area. In each JVM, there is a logical storage area called the method.
the information of the loaded class data in the method area includes:
(1): Basic Information:
1) fully qualified names of each class
2) fully qualified names of direct superclasses of each class (constrained type conversion)
3) whether the class is a class or an interface
4) this type of access modifier
5) ordered list of fully qualified names of the direct superinterface
(2): details of each mounted class:
1) runtime constant pool:
JVM maintains a constant pool for each loaded type. The constant pool is an ordered set of constants used for this type, including actual constants (string,
integer, and floating point constants) and pair types, symbol reference of fields and methods. The data items in the pool are accessed through indexes like array items.
because the constant pool stores symbolic references of all types, fields, and methods used by a type, it plays a core role in Dynamic Links of Java programs.
2) Field Information:
information about each field declared in the class (field name, type, modifier ).
3) method information:
information about each method declared in the class (name, return type, parameter type, modifier, method and exception table ).
4) static variables (class variables) are modified with the keyword static. When the class is loaded, the memory of the class variables is allocated, in the future, when the Instance Object of the class is generated, the memory (class variable) will be shared. Any modification to the class change volume of any object will affect other objects. There are two external access methods: access through an object or access through a class name.
5) to class classloader reference: refers to the Class Loader reference of this class.
6) Reference to class:
A virtual machine creates a class instance for each mounted type to represent the mounted class.
The method area is shared by multiple threads, so there will be thread security issues.
The compiler willSource codeWhen compiled into a bytecode (. Class), the local variables of various types of methods, the size of the operand stack is determined and placed in the bytecode, and loaded into the method area along with the class. When a method is called, access the class information in the method area to obtain the local variables and the size of the operand stack.
That is to say, the variables of some basic types defined in the method and the referenced variables of the object are allocated in the stack memory of the method. WhenCodeWhen a block defines a variable, Java allocates memory space for the variable in the stack. When the scope of the variable is exceeded, Java Automatically releases the memory space allocated for the variable,
The memory space can be used as another memory immediately.
Q: Which allocation exists in the method area?
A separate piece of memory is a memory area that is equal to the heap memory and stack memory. In a JVM, there is only one method area and multiple threads are shared. For example, there is a set method that is executed by threads a and B. Where is the set method? Obviously, it is stored in the method area. So why is there a method stack, that is, the memory area for storing frames, because the method will be transferred to the method stack where the thread is located during execution, allocating space for variables, computing logic, etc. A region is required to store the intermediate results of method execution, and the required parameters.
question: where is the information of attribute members in the class stored?
comparison of stack memory and heap memory
both stack and heap use Java to store data in memory. Unlike C ++, Java automatically manages stacks and stacks, and programmers cannot directly set stacks or stacks.
the Java heap is a runtime data zone where objects are allocated space. The advantage of heap is that the memory size can be dynamically allocated, and the lifetime does not need to be notified to the compiler in advance, because it dynamically allocates memory at runtime, java garbage collection
the collector automatically collects unused data. However, the slow access speed is due to the need to dynamically allocate memory during runtime.
the advantage of stack is that the access speed is faster than that of stack, second only to register, and stack data can be shared. However, the disadvantage is that the data size and lifetime in the stack must be fixed, and there is a lack of flexibility. The stack mainly stores some basic types of variables (INT, short, long, byte, float, double, Boolean, char) and object handles.
a very important feature of stacks is that data in stacks can be shared. Suppose we define at the same time:
int A = 3;
int B = 3;
the compiler first processes int A = 3; first, it will create a reference with the variable A in the stack, and then find whether there is 3 in the stack. If not found, it will store 3, then point A to 3. Then process int B = 3. After the referenced variable of B is created,
B is directed to 3 because there is already 3 in the stack. In this way, both A and B point to 3 at the same time.
if A is set to 4 again, the compiler will re-search whether there are 4 values in the stack. If not, it will save 4 and point A to 4; if yes, direct a to this address. Therefore, changing the value of A does not affect the value of B.
note that the sharing of data is different from the sharing of the two objects pointing to one object at the same time, because the modification of a does not affect B, it is completed by the compiler, which helps save space. The memory allocation is as follows:
A variable referenced by an object modifies the internal state of the object, which affects the variable referenced by another object.
String Memory Allocation
String is a special packaging data. Available:
String STR = new string ("ABC ");
String STR = "ABC ";
The first method is to use new () to create an object, which is stored in the heap. Each call creates a new object.
The second is to first create a string class object in the stack to reference the variable STR, and then find whether the stack contains "ABC". If not, store "ABC" into the stack and point STR to "ABC". If "ABC" already exists, direct STR to "ABC ".
Use the equals () method to compare the values in a class. Use the = method to test whether the references of the two classes point to the same object. The example below illustrates 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 new method is used to generate different objects. Each time one is generated.
Therefore, the first method is used to create multiple "ABC" strings. Only one object exists in the memory. This method can save memory space. At the same time, it can improve the program running speed to a certain extent, because the JVM will automatically decide whether to create a new object based on the actual situation of the data in the stack.
For the code of string STR = new string ("ABC");, a new object is created in the heap, regardless of whether the string value is equal, whether it is necessary to create a new object, this increases the burden on the program.
On the other hand, NOTE: When we use a format such as string STR = "ABC";, we always take it for granted that the STR object of the string class is created. Worry trap! The object may not be created! Instead, it may only point to a previously created object.
Only by using the new () method can a new object be created every time. Because the value of the string class is immutable, when the string variable needs to change its value frequently, you should consider using the stringbuffer or stringbuilder class to improve program efficiency.
Java Program Execution Process
These two days I have read the JVM book in depth and recommended it to senior Java Programmers. I understand the underlying and operating mechanisms of Java.
Big help.
I don't want to talk about this nonsense. The subject:
First, understand the specific concepts:
Java JVM memory can be divided into three areas: heap, stack, and Method)
Heap zone:
1. All objects are stored, and each object contains information about the corresponding class. (The purpose of class is to get operation instructions)
2. Only one heap in the JVM is shared by all threads. The JVM does not store basic types and object references, but only stores the object itself.
Stack zone:
1. Each thread contains a stack zone. Only objects of the basic data type and reference (not objects) of custom objects are stored in the stack zone.
2. Data in each stack (original type and Object Reference) are private and cannot be accessed by other stacks.
3. the stack is divided into three parts: basic variable zone, execution environment context, and operation instruction zone (storing operation instructions ).
Method Area:
1. The static zone is shared by all threads like the heap. The method area contains all the class and static variables.
2. The method area contains always unique elements in the entire program, such as class and static variables.
To get a clearer picture of what is happening in the runtime data area, we will prepare two little items (two very simple applets ).
Appmain. Java
Public class appmain // during runtime, JVM puts all appmain information in the Method Area
{
Public static void main (string [] ARGs) // place the main method itself in the method area.
{
Sample test1 = new sample ("Test 1"); // test1 is a reference, so it is placed in the stack. sample is a custom object and should be placed in the heap.
Sample Test2 = new sample ("Test 2 ");
Test1.printname ();
Test2.printname ();
}
} Sample. Java
Public class sample // when running, JVM puts all appmain information into the Method Area
{
/** Example name */
Private name; // after the new sample instance is created, the name reference is put into the stack, and the name object is put into the heap.
/** Constructor */
Public sample (string name)
{
This. Name = Name;
}
/** Output */
Public void printname () // print method itself is placed in the method area.
{
System. Out. println (name );
}
} OK. Let's get started. The starting command is "Java appmain". We will bring our action wizard diagram in the bag and let's go!
The system received the command and started a Java virtual machine process. The process first found appmain from classpath. class file, read the binary data in this file, and then store the class information of the appmain class in the Method Area of the runtime data zone. This process is called the loading process of the appmain class.
Then, the Java Virtual Machine locates the bytecode of the main () method of the appmain class in the Method Area and starts to execute its commands. The first statement of this main () method is:
Sample test1 = new sample ("Test 1 ");
The statement is simple, that is, let the Java Virtual Machine create a sample instance, and make the reference variable test1 reference this instance. It looks like a small case. Let's track the Java Virtual Machine and see how it executes this task:
1. Check the Java Virtual Machine. Isn't it just creating a sample instance? It's simple, so I went straight to the method area and found the type information of the sample class first. The result is: Hey, no @ is found. There is no sample class in the method area. The Java virtual machine is not an idiot, so it carries forward the style of "self-built, full-fledged", immediately loads the sample class, and stores the type information of the sample class in the method area.
2. Well, the information is found. Let's get started. The first thing Java virtual machine does is allocate memory for a new sample instance in the heap area. This sample instance holds a reference to the type information of the sample class pointing to the method area. The reference here actually refers to the memory address of the sample class type information in the method area. In fact, it is a bit similar to the pointer in C language ~~, This address is stored in the data area of the sample instance.
3. In the Java Virtual Machine Process, each thread has a method call stack to track a series of method call processes in the thread running. Each element in the stack is called a stack frame, every time a thread calls a method, a new frame is pushed to the method stack. The frame here is used to store method parameters, local variables, and temporary data during calculation. OK. After the principles are completed, let's continue our tracking operations! Test1 located before "=" is a variable defined in the main () method. It is visible that it is a local variable. Therefore, it is added to the execution of main () the method is in the Java method call stack of the main thread of the method. "=" Points the test1 variable to the sample instance in the heap area, that is, it holds a reference pointing to the sample instance.
Okay. So far, the Java Virtual Machine has completed the execution of this simple statement. Based on our action wizard diagram, we finally figured out a little bit of details about the Java Virtual Machine, cool!
Next, the Java Virtual Machine will continue to execute subsequent commands, create another sample instance in the heap area, and then execute their printname () method in sequence. When the Java virtual machine executes the test1.printname () method, the Java Virtual Machine locates the sample instance in the heap area based on the reference held by the local variable test1, and then based on the reference held by the sample instance, locate the sample class type information in the method to obtain the bytecode of the printname () method, and then execute the commands contained in the printname () method.
2. Summary of the use of final keywords
2. 1 Scope of variables modified by the final keyword
The final keyword is nothing more than a global variable. When a global variable is modified, the scope is a global variable, and a local variable is modified, java is different fromC LanguageThe final method is used to modify the local variable without changing the scope of the variable. After the method is executed, the frame memory of the method is released. The variable is destroyed, and the objects in the heap are waiting for GC to be recycled.
2.2 final type Initialization
First case: Used as a global constant. Display Initialization is required during definition. If display Initialization is not performed during definition, initialization must be performed in the constructor.
Class student {
String name;
Int age;
Final teacher TC;
Public void Study (){
}
Public student (string name, int age ){
TC = new teacher ();
}
Public student (){
This (null, 0 );
}
}
Class teacher {
Int num;
String name;
Int age;
}
The second case is used in functions,
Public void startthread (){
Final student stumain = new student ();
Final teacher;
New thread (New runnable (){
@ Override
Public void run (){
Stumain. Study ();
Teacher = new teacher (); // This line of code reports an error
}
}). Start ();
}
2.3 When should I use final to modify local variables in a function?
When you need to use global variables in a function, you can create a final type variable and assign the reference of global variables to the final variable, because local variables are stored in the method stack, the addressing speed is faster.
In addition, when function B is called in function a, if the function body of function B is not very large, function B is declared as final. during compilation, function B is directly embedded in function a to call function B.
For example:
See the following test code and I will execute it five times:
-
- Public class test
-
- {
-
- Public static void getjava ()
-
- {
-
- String str1 = "Java ";
-
- String str2 = "final ";
-
- For (INT I = 0; I <10000; I ++)
-
- {
-
- Str1 + = str2;
-
- }
-
- }
- Public static final void getjava_final ()
-
- {
-
- String str1 = "Java ";
-
- String str2 = "final ";
-
- For (INT I = 0; I <10000; I ++)
-
- {
-
- Str1 + = str2;
-
- }
-
- }
-
- Public static void main (string [] ARGs)
-
- {
-
- Long start = system. currenttimemillis ();
- Getjava ();
-
- System. Out. println ("the execution time of the method without final modification is:" + (system. currenttimemillis ()-Start) + "Millisecond Time ");
-
- Start = system. currenttimemillis ();
-
- String str1 = "Java ";
-
- String str2 = "final ";
-
- For (INT I = 0; I <10000; I ++)
-
- {
-
- Str1 + = str2;
-
- }
- System. Out. println ("normal execution time:" + (system. currenttimemillis ()-Start) + "Millisecond Time ");
-
- Start = system. currenttimemillis ();
-
- Getjava_final ();
-
- System. Out. println ("the execution time for calling the final modifier method is:" + (system. currenttimemillis ()-Start) + "Millisecond Time ");
-
- }
-
- }
Result:
First time:
The execution time for calling methods without final modification is 1732 milliseconds.
The normal execution time is 1498 milliseconds.
The execution time of the final modification method is 1593 milliseconds.
Second:
The execution time for calling methods without final modification is 1217 milliseconds.
The normal execution time is 1031 milliseconds.
The execution time of the final modification method is 1124 milliseconds.
Third time:
The execution time for calling methods without final modification is 1154 milliseconds.
The normal execution time is 1140 milliseconds.
The execution time of the final modification method is 1202 milliseconds.
Fourth:
The execution time for calling methods without final modification is 1139 milliseconds.
The normal execution time is 999 milliseconds.
The execution time of the final modification method is 1092 milliseconds.
Fifth:
The execution time for calling methods without final modification is 1186 milliseconds.
The normal execution time is 1030 milliseconds.
The execution time of the final modification method is 1109 milliseconds.
From the above running results, it is not difficult to see that the fastest execution is "normal execution", that is, code is directly written, and the final modification method is not like some books orArticleAs mentioned above, the speed and efficiency are the same as the "normal execution", but they are placed in the second place. The worst is to call methods without final modification.
2.4 lifecycle of variables modified by final in the function
After the function body ends, does the variable still exist?
Public static void main (string [] ARGs ){
Final integer x = 50;
New thread (New runnable (){
@ Override
Public void run (){
While (x> 0 ){
Breakpoint 2: system. Out. println ("the X is:" + x );
Try {
Thread. Sleep (1*1000 );
} Catch (interruptedexception e ){
E. printstacktrace ();
}
}
}
}). Start ();
Breakpoint 1: system. out. println ("the main is over: **************************************** *****************"
+ Thread. currentthread (). GETID () + "");
}
Print result:
The main is over: **************************************** * ***************** 1
The X is: 50
The X is: 50
The X is: 50
The X is: 50
The X is: 50
The X is: 50
The X is: 50
The X is: 50
The X is: 50
The X is: 50
After the main method is executed, X should be destroyed, so the natural sub-thread should also be stopped, but why is the sub-thread not stopped?
Break the breakpoint and debug it. In breakpoint 1, stop and check the variable.
F8 jumps to breakpoint 2, and the main thread has ended.
Comparing the two figures, we can see that the two X in the main thread and sub-thread are not at all one, that is, the anonymous internal class maintains a variable reference. And the variable X in the method points to the same object.
The anonymous internal class uses the external variables to be accessed as a hidden field to obtain a reference copy of the variable. Using the final modifier will not only keep the object unchanged, in addition, the compiler will continue to maintain the lifecycle of this object in the callback method.
The final keyword is used to modify the object variable, but the object reference is not allowed to point to other objects. However, the content of the object pointed to by this reference can be changed. For example, the following code:
Public static void main (string [] ARGs ){
Final arraylist <integer> List = new arraylist <integer> ();
Arraylist <integer> list02 = new arraylist <integer> ();
For (INT x = 0; x <100; X ++ ){
List. Add (X );
}
New thread (New runnable (){
@ Override
Public void run (){
For (integer in: List ){
System. Out. println (thread. currentthread (). GETID () + ":" + in );
}
}
}). Start ();
List. Add (1, 101 );
List. Add (1, 1002 );
List. Add (1, 1003 );
List. Add (1, 1004 );
System. Out. println ("main thread is over ");
}
Print result:
Main thread is over
8: 0
8:1
8: 2
.
.
.
8: 99
8:101
8:1002
8:1003
8:1004
2.5 The anonymous internal class in the method uses the local variable in the Method
The compiler specifies that when an anonymous internal class in a method uses a local variable in the method, the local variable must be modified by the final keyword.
Let's take a look at the working principle of GC. Every process in jvm has multiple roots, each static variable, method parameter, and local variable. Of course, this is a guiding type. the basic type cannot be the root, but the root is actually a storage address. at work, GC first traverses the referenced objects from the root and marks them. After recursion to the final end, after all the roots are traversed, the objects not marked are not referenced, objects that can be recycled (some objects have the finalized method, although not referenced, however, the JVM has a dedicated queue to reference them until the finalized method is executed before it is removed from the queue and can be recycled ,)
However, in the callback method of the internal class, S is neither a static variable nor a temporary variable in the method nor a method parameter. It cannot be used as the root, and no variable in the internal class references it, in the internal external method, if the external variable points to another object, the object will lose reference and may be recycled, because most internal class callback methods are executed in other threads, they may still be accessed after being recycled. what is the result?
The anonymous internal class uses the external variables to be accessed as a hidden field to obtain a reference copy of the variable. Using the final modifier will not only keep the object unchanged, in addition, the compiler will continue to maintain the lifecycle of this object in the callback method. Therefore, this is the fundamental significance of final variables and final parameters.