前言
初学jvm,做了简单的整理记录,方便日后回顾
jvm内存模型
在Java程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存;
因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间)。
而这段空间分为五个大部分。
这里是引用
- 程序计数器:程序计数器是指CPU中的寄存器,它保存的是程序当前执行的指令的地址(也可以说保存下一条指令的所在存储单元的地址)
- JVM栈:是Java方法执行的内存模型,Jvm栈中存放的是一个个的栈帧,每个栈帧(包括:局部变量表、操作数栈、运行时常量池(在下文中提到的方法区内)的引用、方法返回地址和一些额外的附加信息)对应一个被调用的方法,当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈
- 本地方法栈:本地方法栈是为执行本地方法(Native Method)服务的
- 堆:Java中的堆是用来存储对象本身的以及数组;
- 方法区:存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等
其中程序计数器、栈、本地方法栈都是线程私有的,而堆和方法区是线程共享的
来一段代码(示例):
class Student{
public int id=1;
public static Student s1 = new Student();
public static void mian(String args[]){
int age = 2;
Student s2 = new Student();
}
}
那么在这段代码中,在实例化类时,数据在内存中是如何存放的呢?
上答案
处于栈中的数据有:方法里的局部变量age以及Student对象的引用s2
处于堆中的数据有:变量s2所指向的对象,变量s1所指向的对象,成员变量id
处于方法区中的数据有:静态变量s1
这里有一点要注意,对于这个静态变量s1,也有说存放于堆中。这并不是错误,只是jdk的版本不同,static在jdk8之前是在方法区,jdk8之后在堆中,但是其实不管在哪里,都不会影响static变量的使用。
这是因为第一,static变量是同一个类所有的对象实例共享的;第二,static变量,在类加载的时候就生成了。
拓展
class Person{
String name;
int age = 18;
}
Person p = new Person();
关于对象初始化顺序:
对象在创建时,首先在堆中分配空间(地址),然后会进行默认的初始化,即name=null age=0,接着才会进行显式初始化,即name=null age=18,如果定义了有参构造器,接下来还会进行构造器的初始化,最后才将对象在堆中的地址赋值给p
总结
简单总结一下jvm的内存结构分配:
栈:一般存放基本数据类型和局部变量
堆:存放对象和数组
方法区:类加载信息,静态变量,常量池
参考资料:
https://www.cnblogs.com/handsomeye/p/5442879.html(大佬对于内存模型的概念知识,非常详尽)
https://www.bilibili.com/video/BV12t411u726(大佬对于内存模型的视频讲解,通俗易懂)