《深入理解Java虚拟机》学习笔记(2)——Java内存区域与内存溢出异常
2018-02-21 21:02
309 查看
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人想出来。
1、Java虚拟机运行时数据区
(1)程序计数器(Program Counter Register)
可看作是当前线程所执行的字节码的行号指示器。
(2)Java虚拟机栈(JVM Stacks)
虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)来存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表所需的内存空间在编译期间完成分配,其存放了编译器可知的各种基本数据类型、对象引用和returnAddress类型(指向了一条字节码指令的地址)。
虚拟机栈的异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展且扩展时无法申请到足够的内存,将抛出OutOfMemoryError异常。
(3)本地方法栈(Native Method Stack)
本地方法栈与虚拟机栈作用类似,区别是虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机使用本地(Native)方法服务。本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。
(1)~(3)是线程私有的内存区域
(4)Java堆(Java Heap)
Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,目的是存放对象实例和数组。Java堆是垃圾收集器管理的主要区域。
Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。
Java堆扩展通过-Xmx和-Xms控制。
如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
(5)方法区(Method Area)
方法区也是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
方法区可通过参数-XX:MaxPermSize设置。
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
(6)运行时常量池(Runtime Constant Pool)
常量池(Constant Pool Table):Class文件的一部分,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
运行时常量池是方法区的一部分,具有动态性,运行期间也可能将新的常量放入池内。
当常量池无法再申请到内存时会抛出OutOfMemoryError异常。
常量池可通过参数-XX:PermSize和-XX:MaxPermSize设置。
(7)直接内存(Direct Memory)
可通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆的最大值(-Xmx指定)一样。
直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现。
2、HotSpot虚拟机对象探秘
(1)对象的创建过程
①虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过,如果没有则必须先执行相应的类加载过程。
②在类加载检查通过后,虚拟机将为新生对象分配内存。分配方式有“指针碰撞”(Bump the Pointer)和“空闲列表”(Free List)。
③内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头)。
④虚拟机对对象头进行必要的设置。
⑤一般来说执行new指令后会接着执行<init>初始化方法。
(2)对象的内存布局
HotSpot虚拟机中对象的内存布局分为3块区域:
①对象头(Header),包括两部分信息:
第一部分是“Mark Word”,用于存储对象自身的运行时数据。
第二部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定对象是哪个类的实例。
②实例数据(Instance Data),是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。
③对齐填充(Padding),仅仅起着占位符的作用。
(3)对象的访问定位
Java程序通过栈上的reference数据来操作堆上的具体对象。主流的访问方式有:
①使用句柄,reference中存储对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的地址。
②直接指针,reference中直接存储对象地址,优点是速度快,HotSpot使用的是这种方式。
附:相关HotSpot VM参数:
-Xms 初始堆大小
-Xmx 最大堆大小
-Xss 设定栈容量
-XX:PermSize 方法区的初始值
-XX:MaxPermSize 方法区的最大值
-XX:MaxDirectMemorySize 直接内存容量,默认和-Xmx一样
-XX:+HeapDumpOnOutOfMemoryError 让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析
1、Java虚拟机运行时数据区
(1)程序计数器(Program Counter Register)
可看作是当前线程所执行的字节码的行号指示器。
(2)Java虚拟机栈(JVM Stacks)
虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)来存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表所需的内存空间在编译期间完成分配,其存放了编译器可知的各种基本数据类型、对象引用和returnAddress类型(指向了一条字节码指令的地址)。
虚拟机栈的异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展且扩展时无法申请到足够的内存,将抛出OutOfMemoryError异常。
(3)本地方法栈(Native Method Stack)
本地方法栈与虚拟机栈作用类似,区别是虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机使用本地(Native)方法服务。本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。
(1)~(3)是线程私有的内存区域
(4)Java堆(Java Heap)
Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,目的是存放对象实例和数组。Java堆是垃圾收集器管理的主要区域。
Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。
Java堆扩展通过-Xmx和-Xms控制。
如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
(5)方法区(Method Area)
方法区也是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
方法区可通过参数-XX:MaxPermSize设置。
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
(6)运行时常量池(Runtime Constant Pool)
常量池(Constant Pool Table):Class文件的一部分,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
运行时常量池是方法区的一部分,具有动态性,运行期间也可能将新的常量放入池内。
当常量池无法再申请到内存时会抛出OutOfMemoryError异常。
常量池可通过参数-XX:PermSize和-XX:MaxPermSize设置。
(7)直接内存(Direct Memory)
可通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆的最大值(-Xmx指定)一样。
直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现。
2、HotSpot虚拟机对象探秘
(1)对象的创建过程
①虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过,如果没有则必须先执行相应的类加载过程。
②在类加载检查通过后,虚拟机将为新生对象分配内存。分配方式有“指针碰撞”(Bump the Pointer)和“空闲列表”(Free List)。
③内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头)。
④虚拟机对对象头进行必要的设置。
⑤一般来说执行new指令后会接着执行<init>初始化方法。
(2)对象的内存布局
HotSpot虚拟机中对象的内存布局分为3块区域:
①对象头(Header),包括两部分信息:
第一部分是“Mark Word”,用于存储对象自身的运行时数据。
第二部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定对象是哪个类的实例。
②实例数据(Instance Data),是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。
③对齐填充(Padding),仅仅起着占位符的作用。
(3)对象的访问定位
Java程序通过栈上的reference数据来操作堆上的具体对象。主流的访问方式有:
①使用句柄,reference中存储对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的地址。
②直接指针,reference中直接存储对象地址,优点是速度快,HotSpot使用的是这种方式。
附:相关HotSpot VM参数:
-Xms 初始堆大小
-Xmx 最大堆大小
-Xss 设定栈容量
-XX:PermSize 方法区的初始值
-XX:MaxPermSize 方法区的最大值
-XX:MaxDirectMemorySize 直接内存容量,默认和-Xmx一样
-XX:+HeapDumpOnOutOfMemoryError 让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析
相关文章推荐
- 《深入理解Java虚拟机》读书笔记:第二章Java内存区域与内存溢出异常
- 《深入理解Java虚拟机》笔记--第二章、Java内存区域与内存溢出异常
- 深入理解Java虚拟机(一)Java内存区域与内存溢出异常
- 《深入理解Java虚拟机》读书笔记:第二章Java内存区域与内存溢出异常
- 深入理解Java虚拟机(第二章):Java内存区域与内存溢出异常
- 《深入理解Java虚拟机》Java内存区域与内存溢出异常
- 深入理解java虚拟机---->java内存区域与内存溢出异常
- 《深入理解Java虚拟机》第2章 Java内存区域与内存溢出异常
- Java内存区域和内存溢出异常(深入理解Java虚拟机)
- 《深入理解Java虚拟机》读书笔记——Java内存区域与内存溢出异常
- 《深入理解Java虚拟机》Java内存区域与内存溢出异常
- 《深入理解Java虚拟机》->Java内存区域与内存溢出异常
- 《深入理解Java虚拟机》读书笔记——Java内存区域与内存溢出异常
- 《深入理解Java虚拟机》笔记二:01-Java内存区域与内存溢出异常
- Java内存区域与内存溢出异常OOM——深入理解Java虚拟机
- 第2章-Java内存区域与内存溢出异常
- 2.java内存区域与内存溢出异常
- Java内存区域与内存溢出异常
- Java内存存放区域与内存溢出异常(一)