Java虚拟机(JVM) | 第一篇:内存结构

一. JVM内存模型

      

      从上图可以知道,JVM的内存模型包括方法区、虚拟机栈、本地方法栈、堆以及程序计数器。

二. 详细介绍

1. 方法区

      方法区是一块所有线程共享的内存区域,用于存储虚拟机加载的类信息,比如类的字段、方法、常量池(用于存放编译器生成的各种符号引用)、静态变量、以及编译器编译后的代码等。

      在JDK 1.6、JDK 1.7中,方法区可以理解为永久区(Perm)。永久区可以使用参数-XX:PermSize和-XX:MaxPermSize指定,默认情况下,-XX:PermSize为16MB,-XX:MaxPermSize为64MB。

      在JDK 1.8中,永久区已经被彻底移除,取而代之的是元数据区,元数据区大小可以使用参数-XX:MaxMetaspaceSize指定。

2. 虚拟机栈

      虚拟机栈是一块线程私有的内存空间,在虚拟机栈中保存的主要内容为栈帧。每一次函数调用,都会有一个对应的栈帧被压入虚拟机栈,每一个函数调用结束,都会有一个栈帧被弹出虚拟机栈。Java虚拟机提供了-Xss参数来指定线程的最大栈空间。

      在一个栈帧中,至少要包含局部变量表、操作数栈和帧数据区几个部分。

2.1 局部变量表

      局部变量表用于保存函数的参数以及局部变量。局部变量表存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(引用指针,并非对象本身),其中64位长度的long和double类型的数据会占用2个局部变量的空间,其余数据类型只占1个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量是完全确定的,在运行期间栈帧不会改变局部变量表的大小空间。

      虚拟机栈中定义了两种异常,如果线程调用的栈深度大于虚拟机允许的最大深度,则抛出StatckOverFlowError(栈溢出);不过多数Java虚拟机都允许动态扩展虚拟机栈的大小(有少部分是固定长度的),所以线程可以一直申请栈,直到内存不足,此时,会抛出OutOfMemoryError(内存溢出)。

2.2 操作数栈

      操作数栈用于保存计算过程中的中间结果,同时作为计算过程中变量临时的存储空间。

2.3 帧数据区

      除了局部变量表和操作数栈外,Java栈帧还需要一些数据来支持常量池解析、正常方法返回和异常处理等,这些数据就保存在帧数据区。大部分Java字节码指令需要进行常量池访问,在帧数据区中保存着访问常量池的指针,方便程序访问常量池。此外,当函数返回或者出现异常时,虚拟机必须恢复调用者函数的栈帧,并让调用者函数继续执行下去。对于异常处理,虚拟机必须有一个异常处理表,方便在发生异常的时候找到处理异常的代码,因此异常处理表也是帧数据区中重要的一部分。

3. 本地方法栈

      本地方法栈用于支持native方法的执行,存储了每个native方法调用的状态。本地方法栈和虚拟机方法栈运行机制一致,它们唯一的区别就是,虚拟机栈是执行Java方法的,而本地方法栈是用来执行native方法的,在很多虚拟机中(如Sun的JDK默认的HotSpot虚拟机),会将本地方法栈与虚拟机栈放在一起使用。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

4. 堆

      堆区是理解Java GC机制最重要的区域。在JVM所管理的内存中,堆区是最大的一块,堆区也是JavaGC机制所管理的主要内存区域,堆区由所有线程共享,在虚拟机启动时创建。堆区用来存储对象实例及数组值,可以认为java中所有通过new创建的对象都在此分配。

      对于堆区大小,可以通过参数-Xms和-Xmx来控制,-Xms为JVM启动时申请的最新heap内存,默认为物理内存的1/64但小于1GB;-Xmx为JVM可申请的最大Heap内存,默认为物理内存的1/4但小于1GB,默认当剩余堆空间小于40%时,JVM会增大Heap到-Xmx大小,可通过-XX:MinHeapFreeRadio参数来控制这个比例;当空余堆内存大于70%时,JVM会减小Heap大小到-Xms指定大小,可通过-XX:MaxHeapFreeRadio来指定这个比例。对于系统而言,为了避免在运行期间频繁的调整Heap大小,我们通常将-Xms和-Xmx设置成一样。

      根据垃圾回收机制的不同,Java堆有可能拥有不同的结构。最为常见的一种构成是将整个Java堆分为新生代和老年代。

      新生代:程序新创建的对象都是从新生代分配内存,新生代由Eden Space和两块相同大小的Survivor Space(通常又称S0和S1或From和To)构成,可通过-Xmn参数来指定新生代的大小,也可以通过-XX:SurvivorRation来调整Eden Space及Survivor Space的大小。

      老年代:用于存放经过多次新生代GC任然存活的对象,例如缓存对象,新建的对象也有可能直接进入老年代。主要有两种情况:①大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配。②大的数组对象,且数组中无引用外部对象。老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。

5. 程序计数器

      程序计数器是最小的一块内存区域,可能是CPU寄存器或者操作系统内存,其主要用于指示当前线程所执行的字节码执行到了第几行,可以理解为是当前线程的行号指示器。字节码解释器在工作时,会通过改变这个计数器的值来取下一条语句指令。 每个程序计数器只用来记录一个线程的行号,所以它是线程私有(一个线程就有一个程序计数器)的。

      如果程序执行的是一个Java方法,则计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是一个本地(native,由C语言编写完成)方法,则计数器的值为Undefined,由于程序计数器只是记录当前指令地址,所以不存在内存溢出的情况,因此,程序计数器也是所有JVM内存区域中唯一一个没有定义OutOfMemoryError的区域。

三. 其他模块

3.1 类加载器

      累加载器负责从文件系统或者网络中加载Class信息,加载的类信息存放于方法区。

3.2 执行引擎

      执行引擎是Java虚拟机的最核心组件之一,它负责执行虚拟机的字节码。

3.3 直接内存

      直接内存并不是虚拟机内存的一部分,也不是Java虚拟机规范中定义的内存区域。JDK1.4中新加入的NIO,引入了通道与缓冲区的IO方式,它可以调用Native方法直接分配堆外内存,这个堆外内存就是本机内存,不会影响到堆内存的大小。

四. 堆内存与非堆内存

4.1 堆内存

      Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。堆的大小可以固定,也可以扩大和缩小。堆的内存不需要是连续空间。

堆内存分配:

      ①JVM初始分配的堆内存由-Xms指定,默认是物理内存的1/64;

      ②JVM最大分配的堆内存由-Xmx指定,默认是物理内存的1/4;

      ③默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;

      ④空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制;

      ⑤因此服务器一般设置-Xms、-Xmx 相等以避免在每次GC 后调整堆的大小。

      说明:如果-Xmx 不指定或者指定偏小,应用可能会导致java.lang.OutOfMemory错误,此错误来自JVM,不是Throwable的,无法用try…catch捕捉。

4.2 非堆内存

      Java 虚拟机管理堆之外的内存(称为非堆内存)。方法区在逻辑上属于堆,但 Java 虚拟机实现可以选择不对其进行回收或压缩。与堆类似,方法区的大小可以固定,也可以扩大和缩小。方法区的内存不需要是连续空间。除了方法区外,Java 虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。例如,JIT 编译器需要内存来存储从 Java 虚拟机代码转换而来的本机代码,从而获得高性能。

非堆内存分配:

      ①JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;

      ②由-XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4;

      ③-XX:MaxPermSize设置过小会导致java.lang.OutOfMemoryError: PermGen space 就是内存溢出。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值