JVM内存模型系列(一)并发的舞台:内存模型-创新互联

Amdahl定律 正逐渐代替 摩尔定律

摩尔定律,通俗的说就是:每18到24个月,集成电路上可容纳的元器件数目便会增加一倍,芯片的性能也会随之翻一番。

成都创新互联是一家集网站建设,中宁企业网站建设,中宁品牌网站建设,网站定制,中宁网站建设报价,网络营销,网络优化,中宁网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。

而Amdahl定律是一个计算机科学界的经验法则,因吉恩·阿姆达尔而得名。它代表了处理器并行运算之后效率提升的能力。

当摩尔定律被认为即将失效,硬件性能快要到达极限时,Amdahl定律发挥了作用,并发处理的广泛应用,能大效率地榨干我们所用机器的运算资源。

多任务(并发)的起源

经常在新闻上看到,什么超级计算机又每秒多少亿运算,但是我们看视频,刷剧可能还是不时会卡。

因为我们现在使用的设备,cpu的运算速度比存储以及网络通信子系统相差非常大。

为了在看视频卡顿的时候,你还能看看PDF,用个计算器算账,多任务就出现了。

另外,在服务端编程这块,多任务是必须的,因为你的软件要同时为很多用户服务,比如说双十一的秒杀,每个顾客的请求,都是计算机要去完成的一个任务。

充分利用计算机的处理能力

说白了,就是程序员要充分利用计算机的处理能力,让业务组件的TPS(transaction per second)足够高。

并发的挑战和福音

写好并发程序是困难的,好在 Java语言和虚拟机提供了非常多并发的工具,降低了并发编程的门槛,让上层编码人员关注业务本身。

当我们在上层熟练业务之余,不妨来了解一下支持我们在业务中,进行并发编程的基石。

硬件的效率和一致性

为了提升效率,我们找房子就先去找中介,而不是一个个房子敲门去问。

同样,cpu为了更高效于存储,通信子系统沟通,就出现了高速缓存。

我们知道,操作系统是管理硬件资源的,那么管理包含 高速缓存 的这种操作系统,就是共享内存多核系统。

这种操作系统下的真实机器 的内存模型(memory model),就会是这个样子:

处理器->高速缓存->缓存一致性协议->主内存

还是上面中介的例子,你可以把 高速缓存, 缓存一致性协议理解为:中介小哥,和中介小哥们在的公司。

缓存一致性协议保证了cpu在访问高速缓存时的正确性,它包含几种典型的协议:

  • • MSI

  • • MESI 这是一种常用的缓存一致性协议

  • • MOSI

  • • Synapse

  • • Dragon Protocol

内存模型的定义 由此引出

内存模型就是:特定的操作协议下,对内存和高速缓存的读写访问的过程抽象。

类比找房子,你是去链家还是贝壳或者安居客呢?他们有差不多的业务流程和服务风格,尽管有些微差异,但都能帮你找到房子。

屏蔽一些恼人的细节

如果你听说过 cpu的乱序执行,jvm的即时编译器也有指令重排序 这两件事情,那么你会好奇:指令不是我在代码里写的那种执行顺序,程序还能正确出结果?

是的,可以!

内存模型就有这一方面的功效,我们先看看 JMM 的历史。

JMM初识

太古早的历史我们不去深究,你需要知道的是,从JDK 5 实现了 JSR-133 这个提案的要求后,Java 内存模型才叫一个成熟。

这是Java面世九年后,在2004年才搞定的,为啥这么慢?因为这个模型

1) 必须严谨

内存访问不会有任何歧义, 不然bug满天飞可就毁了Java这门语言以及后面庞大的生态。

2) 又要宽松

Java本身是要跨平台的,而JVM就是它跨平台的地基。

JVM自己本身非常希望充分利用物理机器的各种优良特性,来取得在这台机器上的更好性能,所以它不得不在多种机器上进行适配调整。

如此Java语言就能在各种机器上有相同的行为表现,不至于出现在C/C++生态里面的,“在我这种机器上可以跑啊,怎么到你哪就各种编译不过,跑着跑着就segment fault 了” 的问题。

主内存 和 工作内存

如果你记得我上面提过的物理机器增加高速缓存后的内存模型,那么这里我们来做一个对比:JMM(Java Memory Model)类比物理机器的内存模型。

物理机器增加高速缓存后的内存模型:

处理器->高速缓存->缓存一致性协议->主内存

JMM:

Java线程->工作内存->Save和Load操作->主内存

请记住,内存是变量的大池子。

当我们 回到 内存模型,就会明白内存模型的实质目的:内存模型就是 定义你写的各种变量的访问规则。

包括:

  • • 实例中的各种字段,属性变量

  • • 静态字段

  • • 数组里面的元素

但是不包括:

  • • 局部变量(方法里面单独声明的,而非类的成员)

  • • 方法参数(方法括号里面的,这是方法调用是,放入各个线程自己的执行栈的)

因为这些是线程私有的,不存在读写竞争。

在理清所有的访问规则前,我们需要知道,变量的访问(读写)在哪里发生?

对于JMM,这一切在主内存和工作内存发生。

主内存

你知道,JVM虚拟机跑起来时,本身会在物理机上占用一块内存,然后它会再划分出一块内存,当作JMM的主内存。

工作内存

虚拟机里面有许多活动的线程,而每个线程拥有自己的工作内存,里面存储了被该线程使用的变量的主内存副本。

线程实际上操作的变量,全是在工作内存里,而不是主内存。

不同线程之间,不会打扰对方的工作内存,不会互相访问。

线程他们总是通过主内存进行变量的同步。

volatile 变量看起来直接驻留在主内存(因为每次读写总是取得最新结果),但实际上也会在线程的工作内存有副本。(特殊的操作顺序性保证了它总是崭新的状态)

和我们通常理解的Java内存区域的异同

如果你了解过Java虚拟机的内存划分,那么你知道它的运行时数据区,分为堆内存,虚拟机栈,本地方法栈,PC程序计数器,方法区。

这和JMM有关系吗?

其实没有任何关系[手动狗头]

但是你硬要联系起来记忆的话,你可以这样理解:

主内存,对应Java堆中的实例的数据部分,存储在物理机的主内存中。

但是不对应堆里面保存的其他数据,说的就是不包括:

* MarkWord
  * 对象hash码
  * GC标志
  * GC年龄
  * 同步锁信息
* KlassPoint
* Padding

而 工作内存 对应 虚拟机栈的部分区域,反映在物理实体上,就是存储在物理机的寄存器和高速缓存中。

再看看这个图,是不是清晰了很多:

下篇预告

在本篇中,我们分享了一些Java内存模型的起源,定义,概览。下一篇就是具体的规则,正是这些规则,保证了我们并发编程的正确性。

如果您感兴趣,欢迎分享给其他小伙伴,谢谢!

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


当前文章:JVM内存模型系列(一)并发的舞台:内存模型-创新互联
地址分享:http://scyanting.com/article/dcgsii.html