1-1 JAVA内存区域 - 运行时数据区

一、运行时数据区的组成

方法区、虚拟机栈、本地方法栈、堆、程序计数器

 

二、各分区主要功能:

 

      1、程序计数器(Program Counter Register):是一块较小的内存空间

简述:虚拟机的多线程与计算机cpu的多进程实现原理基本相同,都是通过分时系统实现多进/线程任务处理,所谓分时系统就是把虚拟机的运行时间分成一个个的小时间片,来供多个线程使用,每个线程只能执行一个时间片的时间,无论当前线程执行到哪,当前线程的时间片用完都需要记录当前执行位置,让出虚拟机空间给下一个线程使用,那么记录的执行位置对于下一次虚拟机继续执行线程来说就显得尤为重要了,虚拟机会为每个线程提供一个线程私有的线程计数器,来记录计数器所对应线程所执行的字节码行号,以便提供虚拟机实现分时系统和过程控制的先决条件。

备注:如果线程执行的是java方法,程序计数器记录的是虚拟机字节码行号,如果执行的是native(本地)方法计数器的值为空(undefined)(java需要通过虚拟机执行,很多c、c++语言编写的native方法不需要透过java虚拟机执行,自然不需要记录行号)程序计数器是java虚拟机中唯一一个没有规定OutOfMemoryError情况的区域。

      2、java虚拟机栈(Java Virtual Machine Stacks):

(虚拟机栈->java线程,栈帧->java方法)

简述:java虚拟机栈的栈元素叫栈帧,栈帧由局部变量表、操作数栈、动态链接和方法出口等信息组成(主要介绍局部变量表和操作数栈)。

局部变量表存放了方法引用的所有基本数据类型、对象的引用和方法的返回目标(returnAddress,是一个字节码指令地址)。

局部变量表的存储单位为slot(32位存储空间),小于32位的数据占用一个slot,对于long、double等64位数据类型则占用两个slot空间。

虚拟机栈对应于java线程,虚拟机栈的生命周期和java线程的周期一致;栈帧的生命周期和java方法一致,每一个java方法的执行到执行结束的过程,对应栈帧从虚拟机栈入栈到出栈的过程,方法中具体的实现对应于一个或多个操作数从操作数栈入栈到出栈,计算结果,结果再入栈并返回的过程。

局部变量表中的变量不可以直接使用,需要将变量通过相关的指令加载到操作数栈才可以使用。

局部变量表在编译期就已经确定大小,运行期间不可更改,局部变量表空间可以复用。

备注:java虚拟机规范中对虚拟机栈区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机栈所允许的深度,会抛出StackOverflowError异常。如果虚拟机栈可以动态扩展,扩展是无法申请到足够的内存,会抛出OutOfMemoryError异常。

      3、本地方法栈(Native Method Stack):

简述:本地方栈的功能同java虚拟机栈的功能类似,本地方法栈主要为虚拟机用到的本地方法(Native)服务,由于java虚   拟机规范中对于本地方法栈中使用的语言、使用的方法、数据结构等没有强制要求,所有具体的虚拟机可以自由实现它,甚至有些虚拟机将本地方法栈和java虚拟机栈合二为一,同java虚拟机一样,本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。

      4、java堆(java Heap)

简述:java堆是java虚拟机中分配内存最大的一块区域,同时被所有线程所共享,虚拟机启动时创建,此内存区域被创建出来的唯一目的就是存放java对象实例,在java虚拟机规范当中规定所有的对象实例以及数组都要在堆上分配,但随着jit编译器的发展和逃逸分析技术的成熟,栈上分配、标量替换等优化技术的应用使得这个规定也不那么绝对了。

堆可以被分配在物理不连续,但逻辑连续的内存空间中。

java堆是垃圾收集器管理的主要区域,很多时候也被成为GC堆。

从内存回收的角度,java堆可以分为新生代和老年代(目的,更快的回收内存)

从内存分配的角度,可以划分为多个线程私有的分配缓冲区(更快的缓冲内存)

备注:当堆中没有内存可以完成实例分配,并且也无法扩展时,将会抛出OutOfMemoryError异常。

      5、方法区(Method Area)

简述:方法区是线程共享的,它是java堆的逻辑分区当中的一部分,但是它有一个别名叫non-heap(非堆),所以我们要把它和java堆做一个区分, 方法区主要用于存放被虚拟机加载过得类的信息、常量、静态变量以及被即时编译器编译过的代码等信息。

方法区可以被分配在物理不连续,但逻辑连续的内存空间中。

在方法区的垃圾回收主要针对常量池的回收和对类型的卸载,但类型卸载的条件相当苛刻,所以该区域的垃圾回收效果不太令人满意,而这部分的垃圾回收又是必要的。

备注:当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

      6、运行时常量池(Runtime Constant Pool)

简述:运行时常量池是方法区的一部分,Class文件中除了存放有类的版本、字段、方法、接口等描述信息,还有一项信息是常量池,存放编译期生成的各种字面量和符号引用,类被加载后,这些内容直接被存放到运行时常量池中;运行时常量池具有动态性,编译期可以将常量放入常量池,同时运行时也可以存储新的常量到常量池中(例如:String.intern()方法)。

备注:当常量池无法再申请到内存时,将抛出OutOfMemoryError异常。

      7、直接内存(Direct Memory)

简述:直接内存并不是运行时数据区域的一部分,也不是java虚拟机规范中定义的内存区域,但是这部分内存也被频繁的使用,而且也可能导致OutOfMemoryError异常出现,JDK1.4中加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,可以有native函数直接申请堆外内存,然后通过一个存储在堆内的DirectByteBuffer的对象对其进行操作,在某些场景下可以极大的提高性能,因为避免了从java堆到native堆来回复制数据。

备注:动态扩展时超出物理内存限制,将抛出OutOfMemoryError异常。

 

感谢阅读:

由于个人水平有限,如果有不对的地方希望各位能够留言指正,谢谢!

参考书籍:

《深入理解java虚拟机》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值