一、基础篇(JVM内存结构)

一.概念

JAVA的JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method)

1)堆区:

a.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)

b.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身

2)栈区:

a.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中

b.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。

c.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

3)方法区:

a.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。

b.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

二.案例解析

Test.java

//运行时, jvm 把Test的信息都放入方法区
public class Test {

	/**
	 * @Description: main方法
	 * @param @param args   
	 * @return void  
	 * @throws
	 * @date 2018-11-27 下午2:01:23
	 */
	public static void main(String[] args) { //main 方法本身放入方法区。
		MyObject test1=new MyObject("测试1");
		test1.printName();
	}

}

MyObject.java

//运行时, jvm 把MyObject的信息都放入方法区
public class MyObject {
	/*范例名称 */ 
	private String name;//new MyObject实例后, name 引用放入栈区里,  name 对象放入堆里
	/*构造方法 */ 
	public MyObject(String name){
		this .name = name;
	}
	/*输出方法*/ 
	public void printName(){//printName方法本身放入 方法区里。
		System.out.println(name);
	}
}

跟着Test代码走一遍(图示):

1)加载Test类:

首先执行指令:“java Test”,系统收到发出的指令,启动一个Java虚拟机进程,这个进程首先从classpath中找到Test.class文件,读取这个文件中的二进制数据,然后把Test类的类信息存放到运行时数据区的方法区中。

2)执行main()方法:

Java虚拟机定位到方法区中Test类的main()方法的字节码,开始执行它的指令。这个main()方法的第一条语句就是:MyObject test1=new MyObject("测试1")。就是让java虚拟机创建一个MyObject 实例,并且使引用变量test1引用这个实例。

具体过程:

a.建立一个MyObject 实例,去方法区先找到MyObject 类的类型信息。首次没找到,方法区里还没有MyObject 类。所以Java虚拟机立即加载了MyObject 类,把MyObject 类的类型信息存放在方法区里。

b.Java虚拟机首先在堆区中为一个新的MyObject 实例分配内存, 这个MyObject 实例持有着指向方法区的MyObject 类的类型信息的引用。这里所说的引用,实际上指的是MyObject 类的类型信息在方法区中的内存地址,而这个地址就存放了在MyObject 实例的数据区里。

c.在JAVA虚拟机进程中,每个线程都会拥有一个方法调用栈,用来跟踪线程运行中一系列的方法调用过程,栈中的每一个元素就被称为栈帧,每当线程调用一个方法的时候就会向方法栈压入一个新帧。这里的帧用来存储方法的参数、局部变量和运算过程中的临时数据。

d.位于“=”前的test1是一个在main()方法中定义的变量,它是一个局部变量,它被会添加到了执行main()方法的主线程的JAVA方法调用栈中。而“=”将把这个test1变量指向堆区中的MyObject 实例,它持有指向MyObject 实例的引用。

e.JAVA虚拟机将继续执行后续指令,执行test1的printName()方法,当JAVA虚拟机执行test1.printName()方法时,JAVA虚拟机根据局部变量test1持有的引用,定位到堆区中的MyObject 实例,再根据MyObject 实例持有的引用,定位到方法去中MyObject 类的类型信息,从而获得printName()方法的字节码,接着执行printName()方法包含的指令。

猜你喜欢

转载自blog.csdn.net/xm393392625/article/details/84564663