JVM运行时内存区系列之堆

22 篇文章 1 订阅
20 篇文章 0 订阅
起笔

今年的五一,大家可能无法领略到“优美逶迤”的山岭和享受“沁人心脾”的山间泉水。但是可以看到博主的“JVM系列的文章”也不算是虚度了五一嘛!(哈哈🎉🎉✨✨✨🎉✨大家五一节快乐!!!)

在这里插入图片描述
参考书籍:“深入理解java虚拟机”

Java堆

Java堆是虚拟机所管理的内存中最大的一块,且所有的对象示例以及数组都应当在堆上分配

Java堆是所有的线程共享的的一块内存区域,在虚拟机启动的时候创建。此内存区域的唯一目的就是存放对象示例。
在这里插入图片描述
从垃圾回收的角度上来看,堆又可以细分为“新生代”(新生代中包含Eden区和两个Survivor区,S1和S0)、“老年代”、“永久代”(jdk1.8之后叫元空间)。

从内存分配的角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB),以提升对象分配时的效率。

当然,无论从什么角度,无论怎么划分,都不会改变Java堆中存储内容的共性:“无论是那个区域,存储的都只能是对象的示例”,将Java堆细分的目的是为了更好的进行回收内存,或者更快的分配内存。

根据“Java虚拟机规范”,Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的,这点就像我们用磁盘空间去存储文件一样,并不要求每个人间都连续存放(这种思想在数据库底层的设计也有所体现)。

jvm中堆空间新生代与老年代的空间分配

新生代中的结构包括:Eden(伊甸),两个survivor区,且他们的比例为6:1:1,而hotspot中默认的堆中新生代与老年代内存的比例为1:2
在这里插入图片描述
上面这张图通过在终端输入jstat -gccapacity 9008(9008表示java程序的Pid),能够看到jvm中堆的相关的信息。

  • S0C:survivor区中的S0
  • S1C:survivor区中的S1
  • EC:表示Eden区
  • OC:表示Old区

看图中数据,能够清晰的知道相关内存区域的比例。

设置新生代与老年代在堆结构中的占比:

  • -XX:NewRatio=2 表示新生代与老年代的比例为1:2
  • 一般在开发中不需要更改队中的内存的比例分配,但是如果说一些老年区的数据比较多的时候,我们要适当的将老年代的比例设置的更大一些

设置新生代中的占比:

  • -XX:SurvivorRatio=8 表示Eden空间与两个Survivr的比例为8:1:1
  • -XX:-UseAdaptiveSizePolicy 关闭自适应的内存分配策略
  • 几乎所有的对象都是在Eden区创建的,但是如果创建的对象大于Eden区的内存大小,就出现垃圾回收
内存分配策略

针对不停年龄段的对象分配原则如下所示:

  • 优先分配到Eden
  • 大对象直接分配到老年代
    • 尽量避免程序中出现过多的大对象
  • 长期存活的对象分配到老年代
  • 动态对象年龄判断
    • 如果Survivor区中相同年龄的所有对象大小的综合大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。
  • 空间分配担保
    • -XX:HandlePromotionFailure
TLAB
  • 从内存模型而不是垃圾收集的角度,对Eden区域继续进行划分,JVM每个线程分配了一个私有缓存区域,它包含在Eden空间内。
  • 多线程同时分配内存时,使用TLAB可以避免这一系列的非线程安全问题,同时还能够提升内存分配的吞吐量,因此我们可以将这种内存分配方式称之为快速分配策略
  • 所有的OpenJDK衍生出来的JVM都提供了TLAB的设计。
  • 尽管不是所有的对象实例都能够在TLAB中成功分配内存,但JVM确实是将TLAB作为内存分配的首选
  • 在程序中,开发人员可以通过选项“-XX:UseTLAB”设置是否开启TLAB空间。
  • 默认情况下,TLAB空间的内存非常小,仅占有整个Eden空间的1%。当然我们可以通过选项“-XX:TLABWasteTargetPercent”设置TLAB空间所占用Eden空间的百分比大小。
  • 一旦对象在TLAB空间分配内存失败时,JVM就会尝试着通过使用加锁机制确保数据操作的原子性,从而直接在Eden空间中分配内存
堆空间常用的参数设置
  • -XX:PrintFlagsInitial :查看所有参数的默认初始值
  • -XX:PringFlagsFinal :查看所有的参数的最终值(可能会存在修改,不再是初始值)
    • 具体查看某个参数的指令:jps:查看当前运行中的进程 jinfo -flag SurvivorRatio 进程id
  • Xms:初始堆空间内存(默认为物理内存空间的1/64)
  • Xmx:处事堆空间的最大值(默认为物理内存空间的1/4)
  • Xmn:设置新生代的大小(初始值和最大值)
  • -XX:NewRatio:配置新生代与老年代在堆结构的占比
  • -XX:SurvivorRatio:设置新生代中Eden和S0/S1空间的比例
  • -XX:MaxTenuringThreshold:设置新生代垃圾的最大年龄
  • -XX:+PrintGCDetails:输出详细的GC处理日志
  • 打印gc简要信息:1 -XX:+PrintGC 2-verbose:gc
  • -XX:+DoEscapeAnalysis 显示开启逃逸分析
  • -XX:+PrintEscapeAnalysis 查看逃逸分析的筛选结果
  • -XX:CompileThreshold 设置热点代码检测中的方法调用计数器的阈值
  • -XX:-UserCounterDecay 控制方法调用技术器中的热度衰减的开闭
  • -XX:CounterHalfLifeTime 设置方法调用计数器中半衰周期的时间,单位是秒
  • -Xint 完全采用解释器模式执行程序
  • -Xcomp 完全采用即时编译器模式执行程序。如果即时编译出现问题,解释器会介入执行。
  • -Xmixed 采用解释器+即时编译器的混合模式共同执行程序。

这篇文章算是对以后文章做铺垫,大家可以带着这篇文章的疑惑去准备看下一篇文章。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值