JVM(2)-- 内存区域

JVM(2)-- 内存区域

在这里插入图片描述

1. 程序计数器(线程私有)

​ 一块较小的内存空间, 是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为“线程私有”的内存。

​ 这个可以理解为程序计数器中只存储当前线程执行程序的行号,一个类指针的数据结构。

​ 我们熟悉的分支操作、循环操作、跳转、异常处理和线程恢复等基础模型都需要依赖这个计数器来完成。

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

2.虚拟机栈(线程私有)

​ 用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法从调用直至 执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

栈帧(Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接 (动态链接),方法返回值和异常分派(Dispatch Exception)。栈帧随着方法调用而创建,随着方法结束而销毁 - 无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束。

3.本地方法区(线程私有)

​ 本地方法区和Java Stack作用类似,区别是虚拟机栈为执行Java方法服务,而本地方法栈则为Native方法服务,如果一个VM实现使用C-linkage模型来支持Native调用,那么该栈将会是 一个C栈,但HotSpot VM直接就把本地方法栈和虚拟机栈合二为一。

4.堆(Heap-线程共享)-运行时数据区

	是被线程共享的一块内存区域,**创建的对象和数组都保存在Java堆内存中,也是垃圾收集器进行垃圾收集的最重要的内存区域**。由于现代VM采用分代收集算法,因此Java堆从GC 的角度还可以细分为:新生代(Eden区,来自Survivor区和Survivor区)和老年代。

5. 方法区/永久代(线程共享)

​ 即我们常说的永久代(Permanent Generation),用于存储被JVM加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。 HotSpot VM把GC分代收集扩展至方法区,即使用Java堆的永久代来实现方法区,这样HotSpot的垃圾收集器就可以像管理Java堆一样管理这部分内存,而不必为方法区开发专门的内存管理器(永久带的内存回收的主要目标是针对常量池的回收和类型的卸载,因此收益一般很小)。

运行时常量池(Runtime Constant Pool)是方法区 的一部分.Class文件中除了有类的版本,字段,方法,接口等描述等信息外,还有一项信息是常量池(常数池表),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中.Java虚拟机对类文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可,装载和执行。

JVM 运行时内存

Java 堆从 GC 的角度还可以细分为: 新生代(Eden 区From Survivor 区To Survivor 区)和老年代

在这里插入图片描述

1. 新生代

是用来存放新生的对象。一般占据堆的 1/3 空间。由于频繁创建对象,所以新生代会频繁触发MinorGC 进行垃圾回收。新生代又分为 Eden 区、ServivorFrom、ServivorTo 三个区。

1.1Eden

Java 新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。当 Eden 区内存不够的时候就会触发 MinorGC,对新生代区进行一次垃圾回收。

1.2ServivorFrom

上一次 GC 的幸存者,作为这一次 GC 的被扫描者。

1.3ServivorTo

保留了一次 MinorGC 过程中的幸存者。

1.4MinorGC 的过程(复制->清空->互换)

Full GC 和 Minor GC

2.老年代

​ 主要存放应用程序中生命周期长的内存对象。

​ 老年代的对象比较稳定,所以MajorGC不会频繁执行。在进行MajorGC前一般都先进行了一次MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法找到足够大 的连续空间分配给新创建的较大对象时也会提前触发一次。

​ MajorGC采用标记清除算法:首先扫描一次所有老年代,标记出存活的对象,然后回收没有标记的对象 .MajorGC的耗时比较长,因为要扫描再回收.MajorGC会产生内存碎片,为了减少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。当老年代也满了装不下的时候, 就会抛出OOM(Out of Memory)异常。

3.永久代

​ 指内存的永久保存区域,主要存放Class和Meta(元数据)的信息,类在被加载的时候被放入永久区域,它和和存放实例的区域不同,GC不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的类的增多而胀满,最终抛出OOM异常。

JAVA8 与元数据

​ 在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:**元空间并不在虚拟机中,而是使用本地内存。**因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入native记忆,字符串池和类的静态变量放入java堆中,这样可以加载多少类的元数据就不再由MaxPermSize控制,而由系统的实际可用空间来控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值