Java虚拟机内存模
写在前面:
本文是深入理解Java虚拟机第三版(周志明)阅读笔记,图片部分来自电子版书籍
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来。
1 概述
根据《Java虚拟机规范》,Java虚拟机管理的内存包含以下区域:
理解Java虚拟机第三版 图2-1
1.1 程序计数器(Program Counter Register)
程序计数器是一块较小的内存空间,可以看做当前线程执行字节码的行号指示器。
1.2 Java虚拟机栈(Java Virtual Machine Stack)
每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量、操作数栈、动态连接、方法出口等信息。
1.3 本地方法栈(Native Method Stacks)
本地方法栈类似虚拟机栈的作用,区别是虚拟机栈是执行Java方法,本地方法栈是为虚拟机使用本地(Native)方法服务。
1.4 Java堆(Java Heap)
Java堆是虚拟机管理的内存中最大的一块。Java世界里”几乎“所有的对象实例都在堆上分配,《Java虚拟机规范》中对Java堆的描述是:“所有的对象实例以及数组都应当在堆上分配(The Heap is the runtime data area from which memory for all class instances and arrays is allocated)“,但是随着即时编译技术进步,尤其是逃逸分析技术日渐强大,栈上分配、标量替换优化手段导致对象实例都在堆上分配不是这么绝对了。
Java堆是垃圾收集器管理的内存区域,因此有时也被成为“GC堆”,可以通过参数-Xmx 和-Xms 设定堆的大小。‘
1.5 方法区(Method Area)
用于存储已经被虚拟机夹杂的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
1.6 运行时常量池(Runtime Constant Pool)
运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
1.7 直接内存(Direct Memory)
物理机内存,不属于《Java虚拟机规范》中定义的内存区域。
2 HotSpot虚拟机对象探秘
2.1 相关概念
指针碰撞(Bump The Pointer):假设Java堆中内存是绝对规整的,所有被使用过的内存都被放在一边,空闲的内存被放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间方向挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”;
空闲列表(Free List):如果Java堆中的内存并不是规整的,已被使用的内存和空闲的内存相互交错在一起,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”(Free List);
选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有空间压缩整理(Compact)的能力决定。
HotSpot虚拟机里,对象在堆内存中的布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。
对象头(Header):对象头包含两类信息,第一类是存储对象自身运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,又称“Mark Word”;第二类是类型指针,只想它的类型元数据的指针,通过这个指针虚拟机确认这个对象是那个类的实例。
实例数据(Instance Data):对象真正存储的有效信息。
对齐填充(Padding):非必须,占位符作用。


浙公网安备 33010602011771号