JVM 内存模型

it2022-05-05  153

JVM的内存模型按照功能用途,划分为以下几部分: 【程序计数器】 可看作是行号指示器,占用存储空间很小,不会出现OutOfMemory的情况,为线程私有。 如果当前执行的是Java方法,则指示要执行的字节码指令的地址,如果执行的是本地本地方法,则值为Undefined。 生命周期与线程相同。

【虚拟机栈】 可以看作是Java方法栈,是Java方法执行时的内存模型,为线程私有,与线程生命周期相同。 每次方法调用,会创建一个栈帧,栈帧包含的内容如下:

局部变量表: 所需的内存空间在编译期间完成分配。

动态链接: 字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数。这些符号引用一部分在类的加载阶段(解析)或第一次使用的时候就转化为了直接引用(指向数据所存地址的指针或句柄等),这种转化称为静态链接。而相反的,另一部分在运行期间转化为直接引用,就称为动态链接。

每一个方法从被调用到执行完成,对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

内存设置:-Xss?m

【本地方法栈】 与虚拟机栈相似,本地方法栈为JVM使用Native方法服务。 虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。 例如:Sun HotSpot 虚拟机直接就把本地方法栈和虚拟机栈合二为一。

【方法区】 方法区是所有线程共享的内存区。 内容包括:已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 方法区不等同于永久代,在方法区上进行GC是很少出现的,只是HotSpot虚拟机将GC分代收集扩展到了方法区。

运行时常量池: 是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中

内存设置:-XX:PermSize?m -XX:MaxPermSize?m

【堆】 是JVM管理的内存中最大的区域,虚拟机启动时创建,被所有线程共享。 堆上只存放对象实例(JDK1.7 HotSpot将字符串常量池迁移到了堆上面)。 堆中还可以细分为:新生代和老年代。再细致一点划分为:Eden 空间、From Survivor 空间、To Survivor 空间

在为对象分配内存空间时,有两种分配方式: [1] 指针碰撞:要求内存是规整连续的,适用于 GC 方式为 Serial、ParNew等基于压缩收集算法的垃圾收集器; [2] 空闲列表:适用于 GC 方式为 CMS 等基于标记-整理算法的垃圾收集器;

在分配空间时,解决并发分配问题的方案有两种: [1] CAS失败重试:CAS算法 + 循环判断; [2] TLAB(ThreadLocal Allocation Buffer):每个线程预先分配一块内存,内存用完再使用同步分配新的内存空间;

内存设置:-Xms?m -Xmx?m

【直接内存】 在JDK 1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用Native 函数库直接分配堆外内存,然后通过一个存储在Java 堆里面的DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java 堆和Native 堆中来回复制数据。相当于在堆上创建一个对象引用,指向了Native堆中的对象实例。

内存设置:-XX:MaxDirectMemorySize?m

注:以上内容源于《深入理解Java虚拟机》一书。


最新回复(0)