JVM内存区域(基于jdk1.7)

一 程序计数器java

程序计数器是一块较小的内存空间,能够看作当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅仅是概念模型,各类虚拟机可能经过一些更加高效的方式实现),字节码解释器工做时就是经过改变这个计数器的值进行下一条须要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都须要依赖这个计数器来完成。各个线程之间的计数器互不影响,独立存储,为线程私有。数组

若是线程正在执行的是一个java方法,这个计数器记录的是正在执行虚拟机字节码指令的地址,若是是native方法,此计数器则为空(Undefined)。此内存区域是惟一一个在java虚拟机规范中没有规定任何OutOfMemoryError状况的区域。函数

二 虚拟机栈性能

虚拟机栈也是线程私有的,每一个方法执行的同时会建立一个栈帧用于存储局部变量表、操做数栈(保存计算过程的中间结果)、动态连接、方法出口等信息。局部变量表存放着编译器可知的各类基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用类型(因此取对象也是经过此引用获取)。进入一个方法中时,须要在帧中分配多大的局部变量空间是彻底肯定的,在方法运行期间不会改变局部变量表大小。优化

若是线程请求的栈深度大于虚拟机容许的深度,将会抛出StackOverflowError异常;若是虚拟机栈能够动态扩展,当扩展时没法申请到足够的内存,将会抛出OutOfMemoryError异常。我的感受这两个异常只是表述的角度不同,其实是指代同一个东西。spa

三 本地方法栈.net

本地方法栈(Native Method Stack)与虚拟机栈所发挥的做用是十分类似的。惟一的区别是虚拟机栈为虚拟机执行java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的native方法服务。线程

四 堆对象

全部的对象以及数组都要在堆上分配,可是随着JIT编译器的发展和逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会致使一些微妙的变化发生。blog

java堆还能够细分为:新生代和老年代,再细致一点的有Eden空间、From Survivor空间、To Survivor空间等,同时线程共享的堆还能够划分多个线程私有的分配缓冲区。进一步划分的目的是更好的进行内存分配和回收内存。

五 方法区

方法区主要用来存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。须要注意的是"永久区"和方法区并不等价,仅仅是由于HotSpot虚拟机团队把gc分代收集扩展至方法区,或者说用永久代来实现方法区而已,在目前的jdk1.7的HotSpot,已经把本来在永久代的字符串常量池移出。jdk1.8已经把永久代区移出,取而代之的是元数据区。可使用参数-XX:MaxMetaspaceSize指定。

六 运行时常量池

运行时常量池是方法区的一部分,用于存放编译器生成的各类字面量和符号引用,这部份内容将在类加载后进入方法区的运行时常量池中存放。运行期间也能够把新的常量放入池中,像String类的intern()方法即是其中一个应用。常量池的内存受到方法区内存的限制,没法申请到内存时会抛出OutOfMemoryError异常

七 直接内存

直接内存(Direct Memory)并非虚拟机运行时的数据区的一部分,可是这部份内存也被频繁使用,也可能致使OutOfMemoryError异常出现。好比jdk1.4引进的NIO类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可使用Native函数库直接分配堆外内存,而后经过一个储存在java堆中的DirectByteBuffer对象做为这块内存的引用进行操做。这样能在一些场景中显著提升性能,由于避免了java堆和native堆中来回复制数据。

配置虚拟机参数时,每每是根据内存配置-Xmx等参数而忘了直接内存,使得各个区域内存总和大于物理内存限制,从而致使动态扩展时出现OutOfMemoryError异常。

相关文章
相关标签/搜索