`

Java内存区域之运行时数据区域

 
阅读更多

根据《Java虚拟机规范(第二版)》的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域



 

 程序计数器 作用可以看做是当先线程所执行的字节码的信号指示器。

        每一条JVM线程都有自己的程序计数器(“线程私有”内存);

        在任意时刻,一条JVM线程只会执行一个方法的代码。该方法称为该线程的当前方法(Current Method);

        如果该方法是java方法,那程序计数器保存JVM正在执行的字节码指令的地址;

        如果该方法是native,那程序计数器的值是undefined;

        此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

 

虚拟机栈 描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量、操作栈、动态链接、方法出口等信息。

        与程序计数器一样,虚拟机栈也是线程私有,生命周期与线程相同;

        存放编译器可知的各种基本数据类型(boolean、byte、char、shot、int、long、float、double)、对象引用(reference类型,非对象本身)、和returnAddress类型(指向了一条字节码指令的地址);

        64位类型数据会占用2个局部变量空间,其他数据类型只占用1个;

        局部变量表所需的空间在编译器间即完成分配,在方法运行期间不会改变局部变量表的大小;

        在此区域规定了两种异常情况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,当扩展时无法申请到足够的内存时会抛出OutOfMemoryError。 

 

本地方法栈 与虚拟机栈作用类似,区别是为虚拟机使用到的Native方法服务。

        在此处,虚拟机规范没有做强制规定,各厂商可以自由实现。甚至Sun HotSpot虚拟机将本地方法栈与虚拟机栈合二为一。

        此位置也会抛出StackOverflowError和OutOfMemoryError。

 

Java堆 是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存(规范规定:The heap is the runtime data area from which memory for all class instances and arrays is allocated.)。

        Java堆是GC管理的主要区域。从内存回收的角度来看,Java堆可以细分为:新生代和老年代;再细致一些可以分为Eden空间、From Survivor空间、To Survivor空间等;如果从内存分配角度看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB);

        可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可;

        如果在堆中没有足够的内存来完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError。

 

方法区 用于存储已被虚拟机加载的类信息,常量、静态变量、即时编译器编译后的代码等数据。

        被各个线程共享的内存区域;

        对此区域的垃圾回收目标主要在于常量池的回收和对类型的卸载。一般来说对这个区域的内存回收成绩比较难以令人满意,因为类型卸载的条件相当严苛。

        

运行时常量池 存放编译器生成的各种字面常量和符号引用。

        此区为方法区的一部分;

        运行时常量池相比于Class文件常量池的另外一个重要特性是具备动态性,常量并不一定只能在编译期产生,运行期间也可能将新的常量放入池中,例:String的intern()方法

 

直接内存 使用Native函数库直接分配堆外内存。

        并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域;

       因为直接在内存中分配,不会受到Java堆大小的限制,但会受到本机实际内存大小的限制。而且这部分的配置容易被遗忘,在管理员设置 -Xmx等参数时忽略此区域,使得各个内存区域总和比物理内存大小更大。

 

 

 

  • 大小: 62.5 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics