JVM系列_01_JAVA内存区域

1 篇文章 0 订阅

运行时数据区域

  1. Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,根据Java虚拟机规范的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如图 (引用自深入理解Java虚拟机-周志明),其中线程计数器,Java虚拟机栈,本地方法栈是线程私有的,堆,方法区,运行常量池,直接内存是线程共享的。

线程私有

程序计数器

  1. 程序计数器是一个较小的内存空间,字节码解释器是通过改变计数器的值来选取下一条需要执行的指令,分支,循环,跳转,异常处理,线程恢复等都是需要依赖计数器
  2. 多线程是通过线程轮流切换并分配处理器执行时间来实现的,为了保证线程切换回来后还能恢复在正确的执行位置,每个线程都有一个独立的程序计数器,这种每个线程独有的内存区域也叫“线程私有”的内存
  3. 当执行Java方法时,计数器记录正在执行的虚拟机字节码指令的地址,当执行native方法(JNI本地方法)时,计数器的值为空(undefined)
  4. 程序计数器是唯一一个没有规定有OutOfMemoryError的情况的区域

Java虚拟机栈

  1. 是描述Java方法执行的内存模型,方法执行的时候创建一个栈桢(局部变量,操作数栈,动态链接,方法出口等)。方法从调用到执行完成的过程对应该栈桢在Java虚拟机栈中从入栈到出栈的过程。
  2. 我们常说的Java堆栈,其中的栈就是指Java虚拟机栈,准确的说是Java虚拟机栈中的局部变量表,该表存放了编译期可知的8中基本数据类型(boolean,byte,char,short,int,float,long,double 其中long和double是16位,占两个局部变量空间,其余均占一个),对象引用和returnAddress类型(指向了一条字节码指令的地址)
  3. 局部变量表在编译期间完成内存的分配,即当进入一个方法时就已经确定分配,且在方法运行期间不会更改
  4. 在Java虚拟机栈中会有两个异常情况,第一种是StackOverflowError,这是由于线程请求的栈深度大于虚拟机所允许的深度,且无法动态扩展时,目前大多数Java虚拟机都可以动态扩展,当扩展时申请的内存不够时,会抛出第二种异常OutOfMemoryError。
    在这里插入图片描述

本地方法栈

  1. 本地方法栈与Java虚拟机栈只有一个不同,即本地方法栈是服务于native方法,Java虚拟机栈服务与Java方法。同样会抛出两种异常,与Java虚拟机栈一致。

线程共享

Java堆

  1. Java堆通常情况下是Java虚拟机所管理的最大的一块,是被所有线程共享的内存区域,在虚拟机启动时创建。用于存放对象实例,几乎所有对象实例都在这里分配(为什么说几乎,是因为存在逃逸情况,在后面逃逸分析中会再细说)
  2. java堆是垃圾收集管理的主要区域,因此也叫GC堆。首先从内存回收的角度来看,Java堆可以分为新生代,老年代。新生代中又区分Eden空间,To Survivor空间,From Survivior空间。其次如果从内存分配的角度来看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区。无论怎样分配,存放的都是对象实例,划分的目的只是为了更有效的回收内存或分配内存。
  3. Java堆可以是一个不连续的内存空间,在逻辑上连续即可。分配堆大小可以通过 -Xmx 和 -Xms 来控制

方法区

  1. 方法区是用于存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等。是各个线程共享的内存区域。
  2. 通常可以叫做永久代(但是并不相等),是由于HotSpot虚拟机在设计时把GC分代收集扩展至方法区,使垃圾收集器可以像管理Java堆一样管理方法区,使用永久代来实现方法区
  3. 这个区域可以像Java堆一样不用连续的空间,还可以选择不实现垃圾收集(使这部分成为真正的永久代),通常情况下,和Java堆一样由垃圾收集器管理,不过这个区域的回收成绩不令人满意,当方法区无法满足内存分配需求时,会抛出OutOfMemoryError异常
运行时常量池
  1. 运行时常量池是方法区的一部分。一个类文件(class文件)中除了有类的版本,字段,方法,接口描述等,还有常量池,用于存放编译期间生成的各种字面量和符号引用,这部分内容将在类加载之后进入方法区的运行时常量池中存放
  2. 运行时常量池对于class文件常量池的另外一个重要特征是具备动态性,使的运行期间也可以将新的常量放入池中,比如 String类的intern()方法
  3. 内存不足时抛出OutOfMemoryError异常

直接内存

  1. 直接内存并不是虚拟机运行时内存的一部分
  2. 由于NIO(jdk1.4之后)引入基于通道(channel)和缓冲区(Buffer)的I/O方式,可以使用native函数库申请堆外内存,使用Java堆中的DirectByteBuffer对象作为所申请堆外内存的引用来进行操作,这样可以提高性能,避免数据在Java堆和native堆中来回复制,但是也导致了这样操作无法受到Java堆内存的限制,会发生本机总内存被使用过多导致其他区域在申请内存时发生内存不足,从而抛出OutOfMemoryError异常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值