jvm对于java而言非常重要,也是面试时经常遇到的点,自己整理回忆一下jvm的相关知识
jvm中的内存分为5个部分
- 堆
- jvm stack :java虚拟机栈
- 本地方法栈
- 方法区
- 程序计数器
堆
堆中存放着对象实例数据以及数组,数组也是一种特殊的引用类型。对于对象实例而言,并不储存方法,因为方法是指令代码,是储存在stack中的。堆中只保存对象的属性值,属性值的类型,对象本身的类型标记。
gc主要就是回收堆中的对象,因此,堆又可以分为新生代,老年代,新生代又分为edan 和存活区,具体可以看GC的文章。
堆这块内存是线程共享的
jvm stack
jvm stack中放的是方法,java中的方法也就是指令代码,单位是栈帧,每次都是调用一个方法就是一个栈帧入栈,调用完毕就是一个栈帧出栈,调用一个方法的时候会把该方法的局部变量放入栈帧中,形成一个局部变量表。
jvm stack这块内存是独立的,每个线程拥有自己的一个stack
本地方法栈
本地方法栈中放的也是方法,不过是native的方法
同样是独立的
方法区
方法区中存放class文件信息还有常量池,很多字面量和static,final修饰的变量是存放在方法区中的。
常量池中有String常量池,不过1.8以后好像移到堆中了。
方法区是线程共享的
程序计数器
程序计数器是当前线程执行的字节码的行数
程序计数器是独立的(不然怎么标记)
对于java而言,访问一个对象有两种方式
-
直接指针访问
- 句柄访问
假设现在新建了一个对象,A a = new A();
这里的a就是对象引用,是存放在jvm stack中的(?这里面不是放方法的吗)对象引用属于方法内部,所以是在方法栈帧局部变量表里
具体的对象是放在堆中
句柄访问
堆中有一个句柄区,对象引用指向句柄区中的地址
句柄一共记录了两个地址,一个是对象实例数据,在堆中
一个是对象类型数据,保存在方法区中
直接指针访问
对象引用直接指向堆中的对象实例数据
对象实例数据中记录着一个地址,指向方法区中的对象类型数据
对于hotspot虚拟机而言,一般是第二种访问方式(?hotspot)