JAVA虚拟机内存模型概念
(网络图片侵权必删)
从属于线程的内存区域
JVM的内存划分中,有部分区域是线程私有的,有部分是属于整个JVM进程;我们将这部分归为一类
(网络图片侵权必删)
1.程序计数器(Program Counter Register),在JVM规范中,每个线程都有自己的程序计数器。这是一块比较小的内存空间,存储当前线程正在执行的Java方法的JVM指令地址,即字节码的行号。如果正在执行Native方法,则这个计数器为空。
2.Java虚拟机栈(Java Virtal Machine Stack),同样也是属于线程私有区域,每个线程在创建的时候都会创建一个虚拟机栈,生命周期与线程一致,线程退出时,线程的虚拟机栈也回收。虚拟机栈内部保持一个个的栈帧,每次方法调用都会进行压栈,JVM对栈帧的操作只有出栈和压栈两种,方法调用结束时会进行出栈操作。该区域存储着局部变量表,编译时期可知的各种基本类型数据、对象引用、方法出口等信息。
3.本地方法栈(Native Method Stack)与虚拟机栈类似,本地方法栈是在调用本地方法时使用的栈,每个线程都有一个本地方法栈。
堆(heap)
堆(Heap),几乎所有创建的Java对象实例,都是被直接分配到堆上的。堆被所有的线程所共享,在堆上的区域,会被垃圾回收器做进一步划分,例如新生代、老年代的划分。Java虚拟机在启动的时候,可以使用“Xmx”之类的参数指定堆区域的大小。
方法区(Method Area)
方法区与堆一样,也是所有的线程所共享,存储被虚拟机加载的元(Meta)数据,包括类信息、常量、静态变量、即时编译器编译后的代码等数据。
方法区是一种java虚拟机的规范。
由于方法区存储的数据和堆中存储的数据一致,实质上也是堆,因此,在不同的JDK版本中方法区的实现方式不一样。
JDK7以前,方法区就是堆中的“永久代”。
JDK7开始去“永久代”,把静态变量、字符串常量池都挪到了堆内存中。
JDK8以后,“永久代”不存在了。存储的类信息、编译后的代码数据等已经移动到了MetaSpace(元空间)中,元空间并没有处于堆内存上,而是(直接内存)直接占用的本地内存(NativeMemory)。
程序执行的内存分析过程。
java虚拟机的内存可以简单的分为三个区域:虚拟机栈stack、堆heap、方法区method area。
public class Person {
String name;
int age;
public void show(){
System.out.println("姓名:"+name+",年龄:"+age);
}
}
public class TestPerson {
public static void main(String[ ] args) {
// 创建p1对象
Person p1 = new Person();
p1.age = 24;
p1.name = "张三";
p1.show();
// 创建p2对象
Person p2 = new Person();
p2.age = 35;
p2.name = "李四";
p2.show();
}
}
运行上述代码 其虚拟机里的运行如下图所示。
如图所示。
使用mian方法创建一个新的对象为p1,p1调用的是preson类,这时虚拟机里的运行就是在虚拟机栈里面就是在mian方法调用preson方法开辟一个新的内存空间给p1,然后p1的地址为0x1,此时p1为初始值(name=null;age=0;)。
接下来就是代码(“p1.age=24;p1.name=“张三” ;p1.show()”),代码"p1.age=24"就是给p1里面的age赋值为"24",“p1.name=“张三” “就是给p1里面的name赋值为” " 张三” ",最后"p1.show()"就是调用preson里面的 show方法,执行完上述代码之后就会把图中用完的p1.show方法移出栈内(等同于用完就删除不要了)。
下面的代码就和上面p1一样,只不过是赋值不同其他都一样。
总结
了解虚拟机的内存模型概念会有助于理解,脑海里要有一个逻辑,"方法"是拿来用的,"堆 "是来储存你赋值的量,"栈"就是方法使用的地方。