快速理解 JVM 内存模型 & 对象组成 & 对象内存分配

本文详细介绍了JVM内存模型,包括线程共享区域(堆、元空间)与线程独占区域(线程栈、本地方法栈、程序计数器)。同时解析了对象组成(MarkWord、KlassPointer等)及内存分配机制,并讨论了指针压缩技术。

快速理解 JVM 内存模型 & 对象组成 & 对象内存分配

JVM 内存模型

JVM 内存模型分为首先在线程纬度可以分为两部分

一部分是 线程共享: 堆、元空间

  • 堆 : 大多数 new 的对象都存在于堆内,也是 GC 主要回收的空间,占据 JVM 内存的大部分
  • 元空间:存储静态信息,如 常量、静态变量、类元信息(你写的类解析出来的字节码数据),该部分内存空间是直接内存空间。在 cpu 执行权限上,内存分为 用户空间内核空间,对于 JVM 角度来说即 JVM 堆内存区域系统直接内存区域 感兴趣可以浏览文章 零拷贝

一部分是 线程独有: 线程栈、本地方法栈、程序计数器

  • 线程栈: 细分栈帧,线程在执行方法的过程中,每调用一个方法即为该方法分配一块栈帧内存空间,方法调用结束则弹出该栈帧释放栈帧内存空间,每个线程栈空间有限,当你出现循环调用,不停的往线程栈中压入栈帧时,最终就会触发 StackOverFlow 异常。可通过 -Xss 参数配置 (线程栈使用的也是非堆内存,即直接内存)
  • 程序计数器:记录当前线程方法执行位置,用于在线程切换后恢复现场继续执行。
  • 本地方法栈:java 调用本地方法(其他语言的方法,如 C 语言方法)单独区分的栈空间,原理类似于线程栈,有些虚拟机会将其和 线程栈合成一个使用。

在这里插入图片描述

对象组成

在 Java 当中对象在存储时会分为五个部分

  1. Mark Word:属于对象的固有属性,占用 8 byte (字节 ps 1 byte = 8 bit 位)
  2. Klass Pointer 对象指针, 占用 4 byte (开启指针压缩后,Java 1.6 版本后默认开启)。
  3. 数组长度,只有数组对象有,记录数组长度 占用 4 byte。
  4. 实例数据: 这个是我们在定义类时的内部成员变量的占用,是我们开发时经常操作看的到的。
  5. 对其填充: 有时有,会将对象大小补齐为 8 byte 的倍数。

所以,对于一个对象,即使你啥都没有声明,new 出来都至少要占用 8(mark word)+4(klass pointer)+4(对其填充) = 16 byte

说说指针压缩

首先 CPU 分为 32 位寻址 和 64 位寻址,32 位的 CPU 只能处理 32 位故而只能在 2^32 = 4G 内存中寻址,所以 32 位机器和系统只能支持 4G 的内存,现在大部分机器都是 64 位即 2^64 = 18446744073709551616 可支持的理论内存是绝对够人类使用了。

那在 64 位系统下,理论上 JVM 表示一个对象所在内存的地址需要 64 位来表示即 8 byte 字节,那其实大可不必🙅🏻‍♀️

8G 寻址 = 2^33 ,16G 寻址 = 2^34 ,32G 寻址 = 2^35 ,而我们大部分机器基本都在 32G 或之内,所以基本 35 位就可以表示所有内存位置了,JVM 通过算法讲其压缩到 32 位,在到 CPU 寄存器处理时在逆向解压缩出来。指针压缩就是这个道理。

Tips:默认配置下,如果堆内存大于 32G 指针压缩会失效,一般我们最大设置堆内存会设置的比 32G 小一点点,这样可以避免很多麻烦,所以堆并不是越大越好。

指针压缩和类型的对其填充有关,默认对其填充 8 byte 倍数,调高该值可以使指针压缩支持到更大。参考 为什么JVM开启指针压缩后支持的最大堆内存是32G?

对象内存分配

在给对象分配内存的时候,有两种方式

  1. 指针碰撞: 这个是默认的方式,用于规整的 JVM 内存空间进行内存分配 (比如垃圾回收算法使用的是标记整理),这种依次分配的效率是比较高的
  2. 空闲列表:当内存并不规整,而是分散使用时,就需要维护一个空闲位置的列表地址进行分配 (标记清除)

那在分配内存的时候,多线程情况下不可避免会出现抢占问题,解决方案:

  1. 线程本地缓冲 TLAB Thread Local Allocate Buffer: 即预先给每个线程分配一块空间,有些在自己分配的空间中进行分配避免争抢
  2. 比较交换 CAS Compare And Swap + 失败重试:即多个线程争抢一个位置时,先拿到的先分配,其他的失败后重试其他位置分配
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dying 搁浅

两杯酒,一杯敬你余生多欢喜。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值