关闭

Java内存总结

标签: java内存模型总结
199人阅读 评论(0) 收藏 举报
分类:

一、java内存模型
1.内存模型图形

2.重排序
① 源代码
② 编译器重排序
③ 指令级重排序
④ 内存系统重排序
⑤ 最终执行指令序列
指令级重排序和内存系统重排序,属于处理级重排序。
可能会导致多线程出现内存可见性问题,编译器生成指令,会插入特定类型的内存屏障。
2、volatile内存语义的实现

是否能重排 第二个操作
第一个操作 普通读、写 volatile读 volatile写
普通读、写 YES YES NO
volatile读 NO NO NO
volatile写 YES NO NO
1、当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。这个规则确 保volatile写之前的操作不会被编译器重排序到volatile写之后。
2、当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。这个规则确 保volatile读之后的操作不会被编译器重排序到volatile读之前。
3、当第一个操作是volatile写,第二个操作是volatile读时,不能重排序。

1、volatile写之前插入StoreStore屏障;
2、volatile写之后插入StoreLoad屏障;
3、volatile读之后插入LoadLoad屏障;
4、volatile读之后插入LoadStore屏障;
3、锁

在ReentrantLock中,调用lock()方法获取锁;调用unlock()方法释放锁。
ReentrantLock的实现依赖于java同步器框架AbstractQueuedSynchronizer(本文简称之 为AQS)。AQS使用一个整型的volatile变量(命名为state)来维护同步状态,马上我 们会看到,这个volatile变量是ReentrantLock内存语义实现的关键。
4、Final
写final域的重排序规则
禁止把final域的写重排序到构造函数之外。这个规则的实现包含下面2个方面:
1、JMM禁止编译器把final域的写重排序到构造函数之外。
2、编译器会在final域的写之后,构造函数return之前,插入一个StoreStore屏障。这 个屏障禁止处理器把final域的写重排序到构造函数之外。

读final域的重排序规则如下:
1、在一个线程中,初次读对象引用与初次读该对象包含的final域,JMM禁止处理器重排序2、这两个操作(注意,这个规则仅仅针对处理器)。编译器会在读final域操作的前面插入一个LoadLoad屏障。
5、总结
1.jmm内存基本模型

2.Jmm重排序
三个Happen-before:程序顺序性规则、监视器锁规则、volatile规则、传递性。
重排序:编译器重排序、指令级重排序、内存系统重排序。
3.volatile
内存屏障:
volatile写前添加StoreStore屏障;
volatile写后添加StoreLoad屏障;
volatile读后添加LoadLoad屏障;
volatile读后添加LoadStore屏障;
4.final
final读前添加LoadLoad屏障;
final写后添加StoreStore屏障。
final字段不能逃逸构造函数,在访问final字段之前,访问对象之前必须应经被初 始化,初始化对象之前,final字段必须已经被赋值。
5.锁(synchronized、ReentrantLock、concurrent)
AQS中维护一个volatile变量,使用CAS操作内存语义。
二、JVM内存结构
包括:
1、java堆
存储对象,线程共享。OOM
Eden
Old
2、非堆(永久代)
本地方法栈
存储本地方法信息。共有区域。SOF
程序计数器
选择下一条需要执行的字节码指令,分支、跳转、循环等基础功能。私有区域。 OOM
方法区
类型信息(字段、方法)、常量池、静态变量、编译后的代码。共有区域。OOM
JVM栈
栈帧(局部变量表、常量引用、方法返回地址、附加信息、栈计数器),每个方法 调用都创建一个栈帧,该区域是私有的。单线程SOF,多线程OOM。

三、JVM垃圾回收机制
1.垃圾回收算法
标记-清除
标记-(清除)-压缩
复制
增量 分开逐个小区域回收
分代 几个区域不同寿命,一代代回收
并发 停顿
并行 多线程
2、垃圾回收器
年轻代:
Serial:(client模式)
新生代使用复制算法,暂停用户线程;
年老代使用标记整理算法,暂停用户线程;
ParNew:(server模式,多线程版本的Serial收集器)
新生代使用复制算法,暂停用户线程;(多线程)
年老代使用标记整理算法,暂停用户线程;
Parallel Scavenge:(吞吐量优先的收集器)

年老代:
CMS:(响应时间优先(最短回收停顿)的回收器)
使用标记-清除算法
四个阶段:
初始标记
并发标记
重复标记
并发清除

由于CMS会产生浮动垃圾,当回收过后,浮动垃圾如果产生过多,同时因为使用标记-清除算法会产生碎片,可能会导致回收过后的连续空间仍然不能容纳新生代移动过来或者新创建的大资源,因此会导致CMS回收失败,进而触发另外一次FULL GC,而这时候则采用SerialOld进行二次回收。
同时CMS因为可能产生浮动垃圾,而CMS在执行回收的同时新生代也有可能在进行回收操作,为了保证旧生代能够存放新生代转移过来的数据,CMS在旧生代内存到达全部容量的68%就触发了CMS的回收!

Serial Old:(Client)。
年老代使用标记整理算法,暂停用户线程;
Parallel Old:(老生代吞吐量优先的一个收集器)
使用标记整理算法

minorGC:担保GC就是担保minorGC能够满足当前的存储空间,而无需触发老生代的回收,由于大部分对象都是朝生夕死的,因此,在实际开发中这种很起效,但是也有可能会发生担保失败的情况,当担保失败的时候会触发FullGC,但是失败毕竟是少数,因此这种一般是很划算的。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:50438次
    • 积分:973
    • 等级:
    • 排名:千里之外
    • 原创:43篇
    • 转载:33篇
    • 译文:0篇
    • 评论:10条
    最新评论