1.JVM-内存


image

1. 程序计数器

线程私有,每个线程一个

用于存储当前线程执行到哪儿了。

如果线程正在执行一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 方法,这个计数器的值则为 (Undefined)。此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。

2. 虚拟机栈

线程私有,每个线程一个,生命周期和线程一致

描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(StackFrame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。

2.1. 栈帧(StackFrame)

2.1.1. 局部变量表

用于存储编译期可知的各种基本类型(boolean、byte、char、short、int、float、long、double),对象引用(reference 类型)和 returnAddress 类型(指向了一条字节码指令的地址)

在局部变量表中存储数据的单位是 局部变量空间 Slot , long和double会占用2个Slot,其他类型仅占用1个

2.1.2. 操作数栈

操作数栈也常称为操作栈,它是一个先进后出的栈。他的元素是任意的java数据类型,然后对其进行数据操作。

操作数栈被用来进行计算和方法调用时传递参数。

如 加法,运行加法指令的时候会将栈里的前两个数据出栈,然后计算,然后把计算结果入栈。

2.1.3. 动态连接方法

其实就是一个指向该栈帧所属方法在 运行时常量池中的引用。不然你怎么能知道当前栈帧是哪个方法的具体执行呢。

2.1.4. 返回地址

方法返回的情况有两种:正常return (正常完成出口)和遇到异常 异常退出(异常完成出口)

返回值为void方法 最后一句默认为 return 但是可以省略

不管怎么退出当前方法,都会继续执行调用该方法的语句后面的代码,所以方法返回可能需要在 栈帧 中保存一些信息,用来恢复上层方法的执行状态。

3. 本地栈

线程私有,每个线程一个

本地方法栈则为虚拟机使用到的 Native 方法服务

4. 方法区(永久代) PermGen

线程共享,属于共享内存区域

存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

4.1. Class信息

  • 魔数
  • 版本号
  • 父类
  • 接口数组
  • 字段
  • 方法

4.2. 运行时常量池

运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用,但是字符串常量已经在1.7中被移动到字符串常量池中

5. 元数据空间 Metaspace(元空间)

在jdk1.7的HotSpot中,已经把原本放在方法区中的静态变量、字符串常量池等移到堆内存中
在JDK1.8中,HotSpot已经没有“PermGen space”这个区间了,取而代之是Metaspace(元空间)

元空间并没有处于堆内存上,而是直接占用的本地内存(NativeMemory)。

6. 堆

线程共享

主要是存放对象实例和数组

内部会划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。

6.1. 字符串常量池

在开发过程中,字符串类型的数据使用特别频繁。最早在方法区,在1.7版本移入到了堆中,在1.8中永久代变更为元数据空间(MetaSpace),但字符串常量池没有发生变化。

6.2. 新生代

新生代由Eden Space和两块相同大小的Survivor Space(通常又称为S0和S1或From和To)构成

  • Eden Space
  • From Survivor Space
  • To Survivor Space

Eden是对象的出生地,所有新创建的对象都会存到Eden Space中。

Eden Space内存用完之后,创建对象会发现内存不足触发Minor GC 进行回收,回收完成之后,还存活在Eden Space中的对象会被移动 From Survivor Space

Minor GC 触发时还会扫描 From Survivor Space区中的对象,如果对象不再使用了跳过,如果对象在使用,使他们的年龄+1,如果年龄达到条件,这个对象会被复制到老年代中,如果年龄达不到条件会被复制到 To Survivor Space区。Minor GC完成后,清空 From Survivor SpaceTo Survivor Space变成新的 From Survivor Space ,,From Survivor Space变成新的 To Survivor Space。 “To”区被填满之后,会将所有对象移动到年老代。

这么做的好处,如果在一个内存块中执行回收对象的操作,执行完成之后,可使用内存会分布在整个内存块中的各个位置,很难管理,且会产生内存碎片。而且对内存的使用必须使用映射表,无法顺序使用。

总结Minor GC的工作有以下几点:

  • 将不可回收对象从Eden Space移动到From Survivor Space
  • 清空Eden Space
  • 将老年对象从From Survivor Space 移动到 老年代
  • 将年轻对象从From Survivor Space 移动到 To Survivor Space
  • 清空From Survivor Space

6.3. 老年代

7. 直接内存(Direct Memory)

这块内存主要是提供给DirectByteBuffer使用,通过调用Navive函数直接在虚拟机使用的内存外,划分一部分虚拟机外内存供DirectByteBuffer使用。

虽然这块内存不受到Java虚拟机内存的限制,但是还是会受到主机本身的内存限制,也会出现OutOfMemoryError

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值