Java内存模型
2023-04-30 11:18:09   1  举报             
     
         
 AI智能生成
  Java内存模型 思维导图
    作者其他创作
 大纲/内容
  内存区块    
     分支主题  
     分支主题    
     实际上,工作内存、主内存都位于物理内存中  
     内存间交互操作    
     lock(锁定)    
     作用于主内存的变量,把一个变量标识为一条线程独占状态  
     unlock(解锁)    
     作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定  
     read(读取)    
     作用于主内存变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用  
     load(载入)    
     作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中  
     use(使用)    
     作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作  
     assign(赋值)    
     作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作  
     store(存储)    
     作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作  
     write(写入)    
     作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中  
     线程共享    
     方法区    
     存储多种信息    
     类信息  
     常量  
     静态变量  
     及时编译器编译后的代码  
     被描述为堆的逻辑部分  
     1.7之前是使用永久代来实现的方法区    
     容易遇到内存溢出问题  
     1.7中将字符串常量池移出了  
     当方法区无法满足内存分配需求时OOM  
     运行时常量池    
     用于存放class中的常量池数据  
     具备动态性    
     不要求常量一定是编译期产生  
     运行期间也可以放入新的常量    
     利用的最多的就是string.intern()  
     当无法申请到内存时OOM  
     通过 -XX:MaxPermSize 设置大小  
     堆    
     在虚拟机启动时创建  
     用来存放对象实例  
     使用分代回收算法  
     空间非连续  
     会抛出OOM  
     对象的内存布局    
     对象头    
     对象自身运行时数据    
     在32位和64位虚拟机中分别为32bit和64bit  
     官方名 Mark Word  
     与对象自身定义的数据无关的额外存储成本  
     根据对象状态复用自己的存储空间  
     类型指针    
     指向它的类元数据  
     虚拟机通过这个指针来确定对象是哪个类的实例  
     如果对象是数组    
     还有一块用于记录数组长度的数据  
     实例数据    
     程序代码中定义的各种类型的字段内容    
     包括父类继承的还是子类中定义的  
     对齐填充    
     由于hotspot VM的自动内存管理系统要求对象的起始地址必须是8字节的整数倍  
     当实例数据部分没有对齐时,使用对齐填充补充  
     通过-Xmx和-Xms控制大小  
     metaspace    
     1.8  
     不在虚拟机中分配,直接使用本地内存  
     大小只与配置和本地内存大小相关  
     线程隔离(私有)    
     程序计数器    
     记录线程锁执行字节码的行号  
     java方法记录的是正在执行的虚拟机字节码指令地址  
     native方法的话,计数器值为空  
     唯一一个没有OOM的区域  
     虚拟机栈(VM栈)    
     生命周期与线程相同  
     保存线程运行状态  
     描述的是Java方法执行的内存模型  
     最小单位是栈帧    
     局部变量表    
     存放可知的基本数据类型  
     对象引用地址  
     空间以32位为粒度    
     超过64位的数据占用两个变量空间    
     double  
     long  
     操作数栈  
     动态链接  
     返回地址  
     非连续内存空间  
     会抛出异常    
     OOM    
     当栈扩展无法申请到做够的内存时  
     StackOverFlow    
     当线程请求的栈深度超过虚拟机栈深度  
     本地方法栈    
     为虚拟机提供Native方法服务  
     同步原语    
     lock 锁    
     锁的释放 - 获取建立的happens-before关系  
     锁释放和获取的内存语义  
     锁内存语义的实现  
     concurrent包的实现  
     volatile    
     特性    
     可见性:任意线程都volatile最新值都可见  
     原子性:对任意单个volatile变量的读/写具有原子性  
     内存语义    
     当写一个volatile变量时,JMM会吧该线程对应的本地内存中的共享变量刷新到主内存中  
     volatile内存语义的实现  
     JSR-133 增强volatile的内存语义  
     final    
     final域的重排序规则    
     在构造函数内对一个final域的写入,与将final对象赋值给引用变量,这两个操作之间不能重排序  
     初次读取final域的对象引用,与初次读取final域对象,这两个操作之间不能重排序  
     写final域的重排序规则    
     规则    
     JMM禁止编译器把final域的写重排序到构造函数之外  
     JMM会在final域的写之后,构造函数return之前,插入一个storestore屏障。禁止final域的写重排序到构造函数之外  
     确保    
     在对象引用为任意线程可用之前,对象的final域已经被正确初始化,普通域不具有这个保障  
     读final域的重排序规则    
     确保    
     在读一个final域之前,一定先读该final域的对象的引用  
     如果final域是引用类型    
     在构造函数内对一个final引用的对象的成员域的写入,与随后在构造函数外把构造的对象的引用赋值给一个引用变量,这两个操作之间不能重排序  
     为什么final引用不能从构造函数内“逸出”  
     final语义在处理器中的实现  
     JSR133 为什么要增强final的语义    
     只要对象是正确构造的(被构造对象的引用在构造函数中没有溢出),那么不需要使用同步(指lock与volatile的使用)就可以保证任意函数都可以看到final域在构造函数内被初始化后的值  
     重排序    
     数据依赖性  
     as-if-serial语义    
     不管怎么重排序,单线程程序的执行结果不能发生改变  
     程序顺序规则  
     重排序对多线程的影响  
     禁止重排序    
     内存屏障    
     分支主题  
     顺序一致性    
     数据竞争与顺序一致性保证  
     顺序一致性内存模型    
     一个线程中的所有操作必须按照程序的顺序来执行  
     (不管程序是否同步)所有线程都只能看到一个单一的操作执行顺序。在顺序一致性内存模型中,每个操作都必须原子执行且立刻对所有线程可见  
     同步程序的顺序一致性  
     未同步程序的执行特性    
     顺序一致性模型保证单线程内的操作会按程序的顺序执行,而JMM不保证单线程内的操作会按程序的顺序执行  
     顺序一致性模型保证所有线程只能看到一致的操作执行顺序,而JMM不保证所有线程能看到一致的操作执行顺序  
     CPU缓存    
     分支主题  
     缓存结构    
     L1最接近CPU,容量最小,速度最快     数据缓存 L1d Cache, + 指令缓存L1i Cache  
     L2 Cache更大一些,如256K,速度稍慢,一般每个核都要一个独立的L2 Cache  
     L3 Cache多核共用  
     缓存一致性    
     MESI协议    
     M(Modified):这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中  
     E(Exclusive):这行数据有效,数据和内存中的数据一致,数据只存在于本Cache中  
     S(Shared):这行数据有效,数据和内存中的数据一致,数据存在于很多Cache中  
     I(Invalid):这行数据无效  
     缓存行 Cache line    
     64字节    
     缓存最小操作单位    
     如果没有利用好缓存行,可能会遇到性能问题  
     查询缓存行大小    
     $ cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size   
     伪共享(False Sharing)    
     原因    
     多线程时,如需修改“共享同一缓存行变量”,就会无意中影响彼此的性能(互斥)  
     解决原理    
     单个数据填充满一个Cache Line(空间换时间)  
     自动补齐缓存行  
     解决方案    
     1.7    
     // jdk7以下使用此方法13;public final static class VolatileLong13;{13;     public long p1, p2, p3, p4, p5, p6, p7; // cache line padding13;     public volatile long value = 0L;13;     public long p8, p9, p10, p11, p12, p13, p14; // cache line padding13;}  
     1.8    
     @sun.misc.Contended13;public final static class VolatileLong {13;    public volatile long value = 0L;13;    //public long p1, p2, p3, p4, p5, p6;13;}13;13;jvm启动时设置 -XX:RestrictContended  
     缓存失效    
     第一次访问数据,在cache中根本不存在,所以cache miss,可通过 prefetch 解决    
     数据预取  
     cache冲突,通过补齐解决(伪共享的产生)  
     cache满,一般需要减少操作的数据大小,尽量按数据的物理顺序访问数据  
     基础    
     线程通信    
     消息传递  
     共享内存  
     线程同步    
     显式  
     隐式  
     happens-before  
     重排序  
    
 
 
 
 
  0 条评论
 下一页
 为你推荐
 查看更多