Java虚拟机的内存从逻辑的角度上来讲可以分为以下几个类型,
程序计数器
程序计数器是内存中一块比较小的空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。虚拟机通过这个改变这个计数器的值来确定下一条执行的字节码指令
每个线程都有一个独立的程序计数器
- 如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码地址
- 如果执行的是Native方法,这个计数器的数值为空(Undifinded)
栈
和计数器一样,栈也是线程私有的
虚拟机栈
虚拟机栈的生命周期和当前线程相同
虚拟机栈描述的是Java方法执行的内存模型,每个方法被执行的时候都会创建一个栈帧,用于存储局部变量表,操作栈,动态链接,方法出口等信息。
每个方法被调用直到执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
本地方法栈
本地方法栈与虚拟机栈发挥的作用是非常相似的
- 虚拟机栈是描述Java方法调用的栈
- 本地方法栈是描述Native方法调用的栈
Java堆
堆是线程内存共享的一块区域
在虚拟机启动的时候,堆的作用就是存放对象实例
堆是垃圾收集器管理的主要区域,如果从内存回收的角度来看,堆可以细分为新生代和老年代。
如果再细分一点,新生代中还能分为Eden区,To Survivor区,From Survivor区。
新生代的Eden和Survivor:
在新生代中,如果对象第一次被创建的时候,那么都会创建在Eden区。当一次Minor GC触发之后,存活的对象都会被移动到Survivor区中,他们的年龄计数器相对应的+1;
方法区
和堆一样,是线程内存共享的一块区域
用于存储已经被虚拟机加载的类信息,常量,静态变量和即时编译器编译的代码等数据。
运行时常量池
运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。
运行时常量池相较于Class文件常量池的另外一个重要的特征是具备动态性,Java并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,例如String的intern()方法。