JVM内存管理与调优
Java 与 C++ 之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人想出来。
——《深入理解Java虚拟机》周志明
注:本文系《深入理解Java虚拟机》的读书笔记,外带扩展总结,部分内容直接照搬于原文,如有叙述不尽,请阅读原书。 ———-
一、Java内存区域
在以前看的资料中,通常将虚拟机内存划分为堆内存和栈内存。如上图所示,真实的虚拟机内存划分远比这个复杂。我们通常说的栈内存即指虚拟机栈,堆内存就是上图中的“堆Heap”。下面一一介绍虚拟机各个内存区域的作用和特点
1. 程序计数器(Program Counter Register)
- 当前线程执行字节码的行号指示器;
- 线程独立,每个线程都有一个程序计数器;
- 线程执行Java方法,这个计数器存储字节码内存地址;
- 线程执行Native方法,这个计数器值为空(Undefined);
- 唯一一个没有OutOfMemoryError的区域
2. 虚拟机栈(VM Stack)
- 线程私有,生命周期与线程同步
- 每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)
- 存储局部变量表、操作栈、动态链接、方法出口等信息
- 局部变量表存放了编译期可知的各种基本数据类型、对象引用、returnAddress类型(字节码地址)
- 异常:OutOfMemoryError和StackOverflowError
该区域(或局部变量表部分)即我们通常所说的“栈”内存,与“堆”内存对应。
3. 本地方法栈(Native Method Stack)
- 与虚拟机栈所发挥的作用是非常相似的
- 为执行本地方法服务
- 在JDK自带虚拟机HotSpot中,与VM Stack合并
- 异常:同虚拟机栈
4. 堆(Heap)
- 线程共享区域
- 唯一目的:存放对象实例,无论怎么划分区域
- 垃圾管理的主要区域,GC堆(Garbage Collected Heap)
- 分代回收:新生代、老年代
- 细致划分:Eden 空间、From Survivor 空间、To Survivor 空间
- 内存分配角度:线程共享的Java 堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)
- 逻辑连续区域,不要求物理连续
注:内存的大小,会直接影响GC回收时间,Full GC又会停止所有用户进程,从而影响应用相应时间。在内存回收详细讲述。
5. 方法区(Method Area)
- 线程共享区域
- 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
- 堆的逻辑部分(虚拟机规范),但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java 堆区分开来
- 在HotSpot中,也被成为永久代(Permanent Generation、简称Perm),本质上两者并不等价,仅仅是因为HotSpot 虚拟机的设计团队选择把GC 分代收集扩展至方法区,或者说使用永久代来实现方法区而已
- 虚拟机规范中,该区域可以不实现垃圾回收
- 回收是有必要的,在Sun 公司的BUG 列表中,曾出现过的若干个严重的BUG 就是由于低版本的HotSpot 虚拟机对此区域未完全回收而导致内存泄漏
- 异常:OutOfMemoryError
6. 运行时常量池(Runtime Constant Pool)
- 方法区的一部分
- Class 文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中
- 运行时常量池相对于Class 文件常量池的另外一个重要特征是具备动态性,Java 语言并不要求常量一定只能在编译期产生,也就是并非预置入Class 文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String 类的intern() 方法
- 除了保存Class 文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中
- 异常:OutOfMemoryError
7. 直接内存(Direct Memory)
- 并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域
- 在JDK 1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用Native 函数库直接分配堆外内存,然后通过一个存储在Java 堆里面的DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java 堆和Native 堆中来回复制数据
- 收到本机总内存和寻址空间的限制
- 异常:OutOfMemoryError