Java JVM 内存空间解析

 

运行时数据区:

运行时数据区主要分五块,分别是Method Area VM Stack Native Method Stack ,

Heap , program Counter Register

 

Program Counter Register

程序计数器是一小块内存空间,可以看作是当前线程所执行字节码的行号指示器。字节码解释器工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,各类基础功能也都是要依赖这个计数器来实现。

Java虚拟机的多线程是通过线程之间轮流切换并分配处理器的执行时间来实现的。也就是说,任何一个确定的时刻,一个处理器都只执行一个线程。因此为了保证线程切换的正确,每一个线程都有一个程序计数器,各个计数器互相不影响,独立存储。(线程私有内存)

如果线程在执行的是Java方法,那么程序计数器指向正在执行的字节码指令地址;如果一个线程执行的是Native方法,计数器值为空(Undefined)。

 

 

Java virtual Machine Stack

和程序计数器一样,Java虚拟机栈也是线程私有的。它的生命周期与线程相同。虚拟机栈描述的是java方法执行的内存模型:

每个方法在执行的同时都会创建一个Stack Frame 用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用直到执行完成的过程,就对应着一个Stack Frame在虚拟机栈中入栈出栈的过程。

 

许多java程序员口中的栈,指的就是虚拟机栈的局部变量表。局部变量表存放了编译期可知的各种数据类型,包括8种基本类型和对象引用。

Reference类型:它不等同与对象本身,可能是一个指向对象起始地址的指针,也可能是指向一个对象的句柄(二级指针)或与此对象相关的位置,还有可能指向一条字节码指令的地址。

一个局部变量空间占32位,局部变量表在编译期完成分配。当进入一个方法时,这个方法需要在Stack Frame 中分配多大的局部变量空间是已经确定了的,此后大小也不会变化。

 

Java虚拟机规范中定义了两种异常:

1 StackOverflowError :线程请求的栈深度大于虚拟机所允许的深度。(递归调用)

 

 

2OutOfMemoryError : 大部分的虚拟机都支持空间的动态扩展,而如果扩展时无

   法申请到足够的内存,就会抛出此异常。

 

Native Method Stack

    本地方法栈与虚拟机栈的区别就是,虚拟机栈为执行Java字节码服务,本地方法栈为虚拟机使用到的Native方法服务。

虚拟机规范并没有对本地方法栈做使用方式和数据类型的强制规定,所以具体的虚拟机可以自由实现它。

 

Java Heap

   Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存的唯一目的就是存放对象的实例,几乎所有的对象实例(包括数组)都放在这里分配内存。

   Java堆可以处于物理上的不连续的空间(逻辑空间连续即可),实现时,既可以固定大小,也可以是可扩展的。

   当堆中没有内存完成实例分配,并且堆也无法扩展时,会抛出OutOfMemoryError

 

Method Area

Method Area和堆一样是各个线程共享的内存区域。它用于存储被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。

Method Area 也叫Non-Heap,很多人更愿意把它称为Permanent Generation(永生代),事实上,有的虚拟机设计者选择吧GC分代收集扩展到方法区,或者说使用永生代实现方法区,这样JavaGC就可以像管理Heap一样管理MethodArea,省去了专门为MethodArea专门写GC的麻烦。而永生代实现方法区并不是一个好主意,因为更容易出现内存溢出。现在逐渐开始采用Native Memory来实现方法区。

 

Runtime Constant Pool

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

Runtime Constant Pool 相对于Class 文件常量池的一个重要特征就是具备动态性。Java中常量并不是只有在编译期才能产生,也就是并非只有置入Class常量池中的内容才能进入方法区的运行时常量池,运行期间也可以将新的常量放入池中。这种特性被利用的比较多的就是Stringintern()方法。

 

Direct Memory

Direct Memory不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存。但这并非内存也被频繁使用,而且可能导致OutOfMemoryError

直接内存不会受堆大小的限制。由于经常忽略直接内存,所以经常在动态扩展时导致出现OutOfMemoryError异常。

posted @ 2017-03-24 14:48  holos  阅读(266)  评论(0编辑  收藏  举报