Example analysis of JVM memory model and object reference

table of Contents

 

The memory model of JVM has the following settings:

First chestnut 

Second example

The third example:

Fourth chestnut


I rarely see such analysis on the Internet. It turns out that some places are always vague. In fact, there should be more chestnuts to elaborate on the objects. When are the examples? For example, where is the class loading process created? For example, heap or stack, how many have been created? what relationship? On the Internet, there are basically all theories without specific chestnuts. If there are students with good literature in this area, please help me to leave a message and post a link, thank you

The memory model of JVM has the following settings:

1. There is a memory space as main memory, called heap memory.

2. Threads have their own local memory, called thread stack, also called call stack.

3. The thread stack contains information about the method call executed by the current thread, as well as the local variable information of the current method.

4. Each thread can only access its own thread stack and cannot access the thread stacks of other threads.

5. All local variables of primitive types (boolean, byte, short, char, int, long, float, double) are directly stored in the thread stack, and each thread is independent, but a copy of the primitive type can be transferred between threads ( Still can’t be considered shared).

6. Objects of non-primitive types will be stored on the heap, and references to this object will be stored on the stack.

7. The original type in the member method of the object will be stored on the stack.

8. The member variables of the object, including primitive types and packaging types, as well as variables of static type, are stored in the heap along with the class itself.

9. If a thread wants to use the original type member variable of the object, it will copy a copy to its thread stack.

10. If a thread wants to use the object's wrapper type variable, it will directly access the heap.

 

Regarding the above points, the following will use a few simple examples to illustrate, a total of four examples, all the code first, and then analyze separately.

package test;
 
import java.text.SimpleDateFormat;
import java.util.Date;
 
 
public class Test {
 
	public static void main(String[] args) {
		
		case1();
		case2();
		case3();
		case4();
		
	}
	
	public static void case1(){
		
		Test configA=new Test();
		configA.setId(10);
 
		Test configB=configA;
		System.out.println(configA.getId());
		configB.setId(20);
		System.out.println(configA.getId());
 
		System.out.println(configA.hashCode());
		System.out.println(configB.hashCode());
 
	}
	
	public static void case2(){
		
		Test config=new Test();
		config.setTestFieldClass(new TestFieldClass());
 
		TestFieldClass fieldClass=config.getTestFieldClass();
		System.out.println(config.getTestFieldClass().getId());
		fieldClass.setId(20);
		System.out.println(config.getTestFieldClass().getId());
 
		System.out.println(fieldClass.hashCode());
		System.out.println(config.getTestFieldClass().hashCode());
 
	}
	
	public static void case3(){
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
 
        	String a = "1970-01-01";
        	
            Test config=new Test();
            config.setDate(sdf.parse(a));
 
            Date blockTime = config.getDate();
 
            blockTime = sdf.parse("2018-06-28");
            System.out.println(sdf.format(blockTime));
            System.out.println(sdf.format(config.getDate()));
            
 
        } catch (Exception e) {
            e.printStackTrace();
        }
	}
	
	public static void case4(){
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
 
        	String a = "1970-01-01";
        	
            Test config=new Test();
            config.setDate(sdf.parse(a));
 
            Date blockTime = config.getDate();
 
            blockTime.setTime(new Date().getTime());
            System.out.println(sdf.format(blockTime));
            System.out.println(sdf.format(config.getDate()));
            
        } catch (Exception e) {
            e.printStackTrace();
        }
	}
	
	
	public Integer id;
	public Date date;
	public TestFieldClass testFieldClass;
	
	public Date getDate() {
		return date;
	}
 
	public void setDate(Date date) {
		this.date = date;
	}
 
	public Integer getId() {
		return id;
	}
 
	public void setId(Integer id) {
		this.id = id;
	}
 
	public TestFieldClass getTestFieldClass() {
		return testFieldClass;
	}
 
	public void setTestFieldClass(TestFieldClass testFieldClass) {
		this.testFieldClass = testFieldClass;
	}
 
	/**
	 * Test类的成员变量
	 */
	public static class TestFieldClass {
		public Integer id;
 
		public Integer getId() {
			return id;
		}
 
		public void setId(Integer id) {
			this.id = id;
		}
		
	}
}

operation result

10
20
709769211
709769211
null
20
1966953839
1966953839
2018-06-28
1970-01-01
2018-06-28
2018-06-28 

First chestnut 

	public static void case1(){
		
		Test configA=new Test();
		configA.setId(10);
 
		Test configB=configA;
		System.out.println(configA.getId());
		configB.setId(20);
		System.out.println(configA.getId());
 
		System.out.println(configA.hashCode());
		System.out.println(configB.hashCode());
 
	}

10
20
776894132
776894132

Analysis:

1. According to the setting of the memory model, when the code is executed

Test configA=new Test();
configA.setId(10);

When, in fact, an object of the Test class is created in the heap memory, saved in the heap memory, and then pointed to by configA. configA is just a reference in the thread stack, like the following:

2. When the code is executed

Test configB=configA;

At the time, we created a reference to the object of configA (named configB). Note that this reference does not point to configA, but directly points to the object itself in the heap memory, so it becomes the following:

It can be seen that both configA and configB are references to this object, and they share a section of memory.

3. When the code is executed

When configB.setId(20);,
configB sets the id of the object in the heap memory to 20, because configA and configB share the object, so when the id of the configA object is output later, the output is 20, which is as shown in the following figure:

4. Because the two share objects, the hash value output by the code is the same.

 

Second example

	public static void case2(){
		
		Test config=new Test();
		config.setTestFieldClass(new TestFieldClass());
 
		TestFieldClass fieldClass=config.getTestFieldClass();
		System.out.println(config.getTestFieldClass().getId());
		fieldClass.setId(20);
		System.out.println(config.getTestFieldClass().getId());
 
		System.out.println(fieldClass.hashCode());
		System.out.println(config.getTestFieldClass().hashCode());
 
	}

null
20
559102764
559102764

Analysis:

1. The member variable testFieldClass is set in the object config. In this example, the object config is actually stored in the heap memory. The object of the config member variable testFieldClass is also stored in the heap memory, and the config member variable testFieldClass points to this object. The reference, as shown below:

2. When the code is executed

When TestFieldClass fieldClass=config.getTestFieldClass();, the
created fieldClass is actually a reference to this object, and the object itself is stored in the heap memory. At this time, the fieldClass just created is the same as the testFieldClass attribute of the config object, and both point to The reference of this object, as shown below

3. When the code is executed

fieldClass.setId(20);

fieldClass sets the id of this object to 20, which actually modifies the id value of this object in the heap memory, as shown below

Because of this, when config.getTestFieldClass().getId() is output later, the output result is 20.

4. As mentioned earlier, the testFieldClass attributes of the fieldClass and config objects are references to this object, so in the end they output the same hash value, which is 559102764.

 

The third example:

public static void case3(){
		
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	try {
 
            String a = "1970-01-01";
        	
            Test config=new Test();
            config.setDate(sdf.parse(a));
 
            Date blockTime = config.getDate();
 
            blockTime = sdf.parse("2018-06-28");
            System.out.println(sdf.format(blockTime));
            System.out.println(sdf.format(config.getDate()));
            
 
        } catch (Exception e) {
            e.printStackTrace();
        }
}

Pay attention to the output result, the two dates are different:

2018-06-28
1970-01-01

Analysis:

1. The variable blockTime comes from the date attribute in the config variable. At first, the date of blockTime was the initial 1970-01-01, and then the time of blockTime was changed to 2018-06-28. From the output result, the time of variable blockTime Changed, but the date attribute value in the config variable is not modified with the modification of blockTime.

2. At first glance, this example does not conform to the setting of the JVM memory model, because in most cases only the basic type will be stored in the thread stack, and the Date class is not a basic type, it should also be stored in the heap memory, Kind of reference sharing.

3. The reason for the different output of the two dates lies in this line of code:

blockTime = sdf.parse("2018-06-28");
We often call this type of statement with an equal sign an assignment statement, and from the perspective of the memory model, this is not an assignment, but a redirection of references , Although in Date blockTime = config.getDate(); here, the target pointed to by the blockTime reference and the target pointed to by the date parameter of config are still the same, as shown in the following figure:

But when it comes to blockTime = sdf.parse("2018-06-28"); here, the part on the right side of the equal sign creates a new Date object in the heap memory and makes blockTime point the reference to him, that is, from now on The date attribute of blockTime and config is okay, it becomes the following

As you can see, in the whole process, the target referenced by the date attribute of the config has not changed, which is why the above output is different.

 

From the third example above, we can know that non-basic variables are indeed stored in the heap memory, and the redirection of references (equal sign) will make the references directly point to other objects in the heap memory.

The reference point is moved away, what about the previous object? The garbage collector (GC) of the JVM has been waiting. If no one is pointing to an object in the heap memory (or no one is pointing for a period of time, depending on the GC algorithm), the GC will drag the object away and Destroy, and then release the memory he occupied. Of course, the Date object of 1970-01-01 in Example 3 will not be recycled by the GC. Although the point of blockTime is removed, the date attribute of config still points to it.

 

Fourth chestnut

public static void case4(){
		
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
 
            String a = "1970-01-01";
        	
            Test config=new Test();
            config.setDate(sdf.parse(a));
 
            Date blockTime = config.getDate();
 
            blockTime.setTime(new Date().getTime());
            System.out.println(sdf.format(blockTime));
            System.out.println(sdf.format(config.getDate()));
            
        } catch (Exception e) {
            e.printStackTrace();
        }
}

Output result:

2018-06-28
2018-06-28

Analysis:

1. The output time in this example is the same, because the blockTime in this example uses the following method to assign values:

blockTime.setTime(new Date().getTime());
directly changes the content of the blockTime object, instead of changing the reference target in Example 3. The result of this example in the memory model is this:

The above are a few examples of the JVM memory model. Knowing more about the memory model is still very helpful for development work, and you can dig a lot of pits.

 

 

Guess you like

Origin blog.csdn.net/Goligory/article/details/104547880