本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本篇是关于JVM内存的详细分析。网上有很多关于JVM内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是JVMSpecification的定义,一边是HotspotJVM的实际实现,有时候人们一些部分说的是JVMSpecification,一部分说的是Hotspot实现,给人一种割裂感与误解。本篇主要从Hotspot实现出发,以Linuxx86环境为主,紧密贴合JVM源码并且辅以各种JVM工具验证帮助大家理解JVM内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需
本文基于OpenJDK11以上的版本最近爆肝了这系列文章全网最硬核Java新内存模型解析与实验,从底层硬件,往上全面解析了Java内存模型设计,并给每个结论都配有了相关的参考的论文以及验证程序,我发现多年来对于Java内存模型有很多误解,并且我发现很多很多人都存在这样的误解,所以这次通过不断优化一个经典的DCL(DoubleCheckLocking)程序实例来帮助大家消除这个误解。首先有这样一个程序,我们想实现一个单例值,只有第一次调用的时候初始化,并且有多线程会访问这个单例值,那么我们会有:getValue的实现就是经典的DCL写法。在Java内存模型的限制下,这个ValueHolder有两
本篇文章参考了大量文章,文档以及论文,但是这块东西真的很繁杂,我的水平有限,可能理解的也不到位,如有异议欢迎留言提出。本系列会不断更新,结合大家的问题以及这里的错误和疏漏,欢迎大家留言如果你喜欢单篇版,请访问:全网最硬核Java新内存模型解析与实验单篇版(不断更新QA中)如果你喜欢这个拆分的版本,这里是目录:全网最硬核Java新内存模型解析与实验-1.什么是Java内存模型全网最硬核Java新内存模型解析与实验-2.原子访问与字分裂全网最硬核Java新内存模型解析与实验-3.硬核理解内存屏障(CPU+编译器)全网最硬核Java新内存模型解析与实验-4.Java新内存访问方式与实验全网最硬核Ja
本篇文章参考了大量文章,文档以及论文,但是这块东西真的很繁杂,我的水平有限,可能理解的也不到位,如有异议欢迎留言提出。本系列会不断更新,结合大家的问题以及这里的错误和疏漏,欢迎大家留言如果你喜欢单篇版,请访问:全网最硬核Java新内存模型解析与实验单篇版(不断更新QA中)如果你喜欢这个拆分的版本,这里是目录:全网最硬核Java新内存模型解析与实验-1.什么是Java内存模型全网最硬核Java新内存模型解析与实验-2.原子访问与字分裂全网最硬核Java新内存模型解析与实验-3.硬核理解内存屏障(CPU+编译器)全网最硬核Java新内存模型解析与实验-4.Java新内存访问方式与实验全网最硬核Ja
本篇文章参考了大量文章,文档以及论文,但是这块东西真的很繁杂,我的水平有限,可能理解的也不到位,如有异议欢迎留言提出。本系列会不断更新,结合大家的问题以及这里的错误和疏漏,欢迎大家留言如果你喜欢单篇版,请访问:全网最硬核Java新内存模型解析与实验单篇版(不断更新QA中)如果你喜欢这个拆分的版本,这里是目录:全网最硬核Java新内存模型解析与实验-1.什么是Java内存模型全网最硬核Java新内存模型解析与实验-2.原子访问与字分裂全网最硬核Java新内存模型解析与实验-3.硬核理解内存屏障(CPU+编译器)全网最硬核Java新内存模型解析与实验-4.Java新内存访问方式与实验全网最硬核Ja
本篇文章参考了大量文章,文档以及论文,但是这块东西真的很繁杂,我的水平有限,可能理解的也不到位,如有异议欢迎留言提出。本系列会不断更新,结合大家的问题以及这里的错误和疏漏,欢迎大家留言如果你喜欢单篇版,请访问:全网最硬核Java新内存模型解析与实验单篇版(不断更新QA中)如果你喜欢这个拆分的版本,这里是目录:全网最硬核Java新内存模型解析与实验-1.什么是Java内存模型全网最硬核Java新内存模型解析与实验-2.原子访问与字分裂全网最硬核Java新内存模型解析与实验-3.硬核理解内存屏障(CPU+编译器)全网最硬核Java新内存模型解析与实验-4.Java新内存访问方式与实验全网最硬核Ja
12.监控TLAB慢分配与TLAB外分配-JFR相关事件解析我们可以通过JFR来监控TLAB慢分配或者TLAB外分配事件。也就是jdk.ObjectAllocationOutsideTLAB与jdk.ObjectAllocationInNewTLAB这两个事件。jdk.ObjectAllocationOutsideTLAB和jdk.ObjectAllocationInNewTLAB这两个事件在default.jfc中(JFR默认事件采集配置)是没有开启采集的:<eventname="jdk.ObjectAllocationInNewTLAB"><setti
11.TLAB相关JVM日志解析11.1.准备JavaWhiteBoxAPI首先需要准备好JavaWhiteBoxAPI11.1.1.什么是WhiteBoxAPIWhiteBoxAPI是HotSpotVM自带的白盒测试工具,将内部的很多核心机制的API暴露出来,用于白盒测试JVM,压测JVM特性,以及辅助学习理解JVM并调优参数。WhiteBoxAPI是Java7引入的,目前Java8LTS以及Java11LTS(其实是Java9+以后的所有版本,这里只关心LTS版本,Java9引入了模块化所以WhiteBoxAPI有所变化)都是有的。但是默认这个API并没有编译在JDK之中,但是他的实现是编
10.TLAB流程常见问题Q&A这里我会持续更新的,解决大家的各种疑问10.1.为何TLAB在退还给堆的时候需要填充dummyobject主要保证GC的时候扫描高效。由于TLAB仅线程内知道哪些被分配了,在GC扫描发生时返回Eden区,如果不填充的话,外部并不知道哪一部分被使用哪一部分没有,需要做额外的检查,如果填充已经确认会被回收的对象,也就是dummyobject,GC会直接标记之后跳过这块内存,增加扫描效率。反正这块内存已经属于TLAB,其他线程在下次扫描结束前是无法使用的。这个dummyobject就是int数组。为了一定能有填充dummyobject的空间,一般TLAB大小都
9.OpenJDKHotSpotTLAB相关源代码分析如果这里看的比较吃力,可以直接看第10章,热门Q&A,里面有很多大家常问的问题9.1.TLAB类构成线程初始化的时候,如果JVM启用了TLAB(默认是启用的,可以通过-XX:-UseTLAB关闭),则会初始化TLAB。TLAB包括如下几个field(HeapWord*可以理解为堆中的内存地址):src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp//静态全局变量staticsize_t_max_size;//所有TLAB的最大大小staticint_reserve_for_al
8.TLAB基本流程8.0.如何设计每个线程的TLAB大小之前我们提到了引入TLAB要面临的问题以及解决方式,根据这些我们可以这么设计TLAB。首先,TLAB的初始大小,应该和每个GC内需要对象分配的线程个数相关。但是,要分配的线程个数并不一定是稳定的,可能这个时间段线程数多,下个阶段线程数就不那么多了,所以,需要用EMA的算法采集每个GC内需要对象分配的线程个数来计算这个个数期望。接着,我们最理想的情况下,是每个GC内,所有用来分配对象的内存都处于对应线程的TLAB中。每个GC内用来分配对象的内存从JVM设计上来讲,其实就是Eden区大小。在最理想的情况下,最好只有Eden区满了的时候才会G
6.JVM中的期望计算EMA在上面提到的TLAB大小设计的时候,我们经常提到期望。这个期望是根据历史数据计算得出的,也就是每次输入采样值,根据历史采样值得出最新的期望值。不仅TLAB用到了这种期望计算,GC和JIT等等JVM机制中都用到了。这里我们来看一种TLAB中经常用到的EMA(ExponentialMovingAverage指数平均数)算法:EMA算法的核心在于设置合适的最小权重,我们假设一个场景:首先采样100个100(算法中的前100个是为了排除不稳定的干扰,我们这里直接忽略前100个采样),之后采样50个2,最后采样50个200,对于不同的最小权重,来看一下变化曲线。可以看出,最小
4.TLAB的生命周期TLAB是线程私有的,线程初始化的时候,会创建并初始化TLAB。同时,在GC扫描对象发生之后,线程第一次尝试分配对象的时候,也会创建并初始化TLAB。TLAB生命周期停止(TLAB声明周期停止不代表内存被回收,只是代表这个TLAB不再被这个线程私有管理)在:当前TLAB不够分配,并且剩余空间小于最大浪费空间限制,那么这个TLAB会被退回Eden,重新申请一个新的发生GC的时候,TLAB被回收。5.TLAB要解决的问题以及带来的问题与解决方案的思考TLAB要解决的问题很明显,尽量避免从堆上直接分配内存从而避免频繁的锁争用。引入TLAB之后,TLAB的设计上,也有很多值得考虑
1.观前提醒本期内容比较硬核,非常全面,涉及到了设计思想到实现原理以及源码,并且还给出了相应的日志以及监控方式,如果有不清楚或者有疑问的地方,欢迎留言。其中涉及到的设计思想主要为个人理解,实现原理以及源码解析也是个人整理,如果有不准确的地方,非常欢迎指正!提前感谢~~2.分配内存实现思路我们经常会new一个对象,这个对象是需要占用空间的,第一次new一个对象占用的空间如图00所示,我们这里先只关心堆内部的存储,元空间中的存储,我们会在另一个系列详细讨论。堆内部的存储包括对象头,对象体以及内存对齐填充,那么这块空间是如何分配的呢?首先,对象所需的内存,在对象的类被解析加载进入元空间之后,就可以在