在面试中被问到了Java内存管理和GC,我对这个的理解还比较表面,现在来整理下这方面的知识。
Java 内存管理
Java 使用JVM进行内存管理,JVM将内存分为五大区,下面分别进行介绍:
1. 程序计数器
程序计数器可以看成是当前字节码的行号指示器。JVM的字节码解释器就是改变程序计数器的值,来选择下一条要执行的指令。(跟X86CPU的CS:IP寄存器很像)
程序计数器是单一线程独享的,保证进程之间独立操作,不会相互影响。
此内存区域不会产生OutOfMemoryError的情况。
2. java虚拟机栈
虚拟机栈是线程私有的,它的生命周期与线程相同。
虚拟机栈描述的是java方法执行时的内存模型,每个方法执行时会创建一个栈帧来创建局部变量表,操作数栈,动态链表,方法入口等信息。
每一个方法从调用直至完成的过程,对应一个栈帧从虚拟机栈入栈到出栈的过程。
如果扩展时无法申请到足够的内存,会产生OutOfMemoryError错误。
局部变量表中存储着方法的相关局部变量,包括各种基本数据类型,对象的引用,返回地址等。在局部变量表中,只有long和double类型会占 用2个局部变量空间(Slot,对于32位机器,一个Slot就是32个bit),其它都是1个Slot。需要注意的是,局部变量表是在编译时就已经确定 好的,方法运行所需要分配的空间在栈帧中是完全确定的,在方法的生命周期内都不会改变。
3. 本地方法栈
本地方法栈与Java虚拟机栈类似,不同的是,本地方法栈为虚拟机使用到的Native方法服务。
有的虚拟机会把本地方法栈和虚拟机栈合二为一。
4. java堆
Java堆是所有对象共享的一块内存区域,在虚拟机启动时产生,此内存区域的作用是存放对象实例。
Java堆是JVM GC的主要区域,现在的JVM基本采用分代回收算法,将对象实例分为新生代和老生代。
共享的Java堆可能会被JVM划分为多个线程私有的分配缓冲区。
Java堆处于物理上不连续的空间,但必须在逻辑上连续。
5. 方法区
方法区是被多个线程共享的内存区域,用于存储已被虚拟机加载的类信息,常量,静态变量,及时编译器编译后的代码等数据。
GC回收再这个区域较少,这个区域的回收目标是针对常量池的回收和类型卸载。
Java对象的访问机制
一般来说,一个Java对象的访问涉及到三种内存区域
JVM栈,堆,方法区
以简单的对象访问为例 Object o = new Object();
- new Object()作为实例对象存储在堆中。
- 堆中还记录的Object对象的类型信息的地址。这些地址所执行的数据存储在方法区中。
通过句柄访问堆中对象
通过句柄访问时,JVM堆中会分配一个句柄池,存储相关句柄执行的实际地址,此方法访问十分稳定。
通过直接指针访问
reference存储的就是对象在堆中的实际地址,堆中存储的对象信息包含了在方法区中的相应数据。
图片整理自网络,下篇介绍Java GC机制。