JAVA虚拟机运行时数据区域

  方法区(Method Area) 虚拟机栈(VM Stack) 本地方法栈(Native Method Area) Java堆(Heap) 程序计数器(Project Counter Register) 执行引擎、本地库接口、本地方法库。

1.程序计数器

  它是一个很小的内存空间,可看做当前线程做执行的字节码的行号指示器。若当前执行Java程序,则计数器记录的为正在执行的虚拟机字节码指令的地址。若当前执行的是本地方法,则计数器记录的值为空(Undefined)。

  Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式实现的,在任何一个确定的时刻,一个处理器(对于多核处理器则为一个内核)都会执行一条线程中的指令。所以为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,即为"线程私有"内存。

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

2.Java虚拟机栈

  线程私有,生命周期与线程相同。

  虚拟机栈描述的是Java方法执行的内存模型:方法执行创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。方法从执行至完成=栈帧在虚拟机栈中入栈至出栈。

  局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,指向对象起始地址的引用指针、句柄或者相关位置)和returnAddress类型(指向下一条字节码指令地址)。

  64位长度long和double类型的数据会占用2个局部变量空间,其余占1个。

  局部变量表所需的内存空间在编译期间完成分配且不会改变局部变量表的大小。

  Java虚拟机规范中,对此区域规定两个异常状况:

  ①如果线程请求的栈深度大于虚拟机所允许的深度,抛StackOverflowError异常。

  ②如果虚拟机栈可以动态扩展(当前大部分Java虚拟机都可动态扩展,Java虚拟机规范也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

3.本地方法栈

  作用与虚拟机站相似,区别:虚拟机栈为虚拟机执行Java方法(字节码)服务,本地方法栈为虚拟机使用Native方法服务。

  虚拟机规范对本地方法栈中方法使用的语言、方法与数据结构并没用强制规定,有些虚拟机直接把它与虚拟机栈合二为一(Sun HotSpot)。

  也会抛出StackOverflowError和OutOfMemoryError异常。

4.Java堆

  Java虚拟机中最大的内存空间,多线程共享,存放对象实例,几乎所有对象实例都在这里分配内存,“几乎”是由于JIT逃逸分析技术

  又称为“GC堆”,采用分代收集法,可细分为:新生代和老生代;再细分有Eden空间、From Survivor空间和To Survivor空间等。从内存分配来看,线程共享的Java堆可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)

  通过-Xmx和-Xms控制是否可扩展,如果堆没有内存完成实例分配,则抛出OutOfMemoryError异常。

5.方法区

  多线程共享,存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。

  虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但有别名叫Non-Heap,目的可能为了与Java堆区别。

  有人称方法区为“永生代”,因为HotSpot虚拟机设计团队把GC分代收集扩展到方法区,可以像管理Java堆一样管理这部分内存,省去方法区编写内存管理代码。但由于更容易内存溢出(永生代有-XX:MaxPermSize上限)而且极少数方法(String.intern())会导致不同虚拟机下不同的表现,JDK1.7已把永生代的字符串常量池移除。

  垃圾回收在这个区域较少出现,内存回收主要目标是针对常量池的回收和对类型的卸载,回收效果不理想。

  无法满足内存分配需求是,抛出OutOfMemoryError异常。

6.运行时常量区

  是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期产生的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。还有翻译出来的直接引用也会存在该区域。

  运行时常量池对Class文件常量池具备动态性,运行期间也可能将新的常量放入池中。

  受方法区内存限制,无法再申请内存抛OutOfMemoryError异常。

7.直接内存

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

  JDK1.4新加NIO(New Input/Output)引入基于通道(channel)与缓冲区(buffer)的I/O方式,可通过Native库直接分配堆外内存,再通过Java堆中的DirectByteBuffer对象作为引用进行操作,避免Java堆与Native堆来回复制数据,提高性能。

  由于直接内存不受Java堆限制,设置-Xmx等参数,若忽略直接内存参数,使得各个内存区域大于物理内存区域,抛OutOfMemoryError异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值