专栏首页编程坑太多JAVA线程-CPU缓存和内存屏障(四)

JAVA线程-CPU缓存和内存屏障(四)

上节说了线程中止,优雅和暴力的方式,也说到了通过标志位的方式,这次一起说说CPU缓存和内存屏障。

(一)CPU性能优化手段

  • ① 缓存

为了提高程序运行的性能,CPU已经i7 10代了,很多方面对程序进行优化。 CPU 告诉缓存,硬盘很慢,运用缓存加载到内存里面,提高的访问速度,尽可能地避免处理器访问主内存的时间开销,处理器大多会一用缓存(cache)以提高性能。这也是目前大部分的处理器使用的机制,处理器的缓存。

  • ② 多级缓存

L1 Cache (一级缓存)是CPU第一层高速缓存, 分为数据缓存和底层的指令缓存, 一般服务器CPU的L1缓存的容量通常在32-4096kb。

L2 Cache (二级缓存) 由于L1高速缓存的容量限制, 为了再次提高CPU的运算速度, 在CPU外部放置一高速缓存存储器, 即二级缓存。

L1和L2前面的容量都是有限的,就提出了L3,L3 Cache(三级缓存)现在都是内置的, 而它的实际作用既是, L3缓存的应用可以进一步降低内存延迟, 同时提升大数据量计算时处理器的性能. 具有较大L3缓存的处理器更有效的文件系统缓存行为及较短消息和处理器队列长度. 一般是多核共享一个L3缓存。不管你电脑有多少个CPU,每个CPU都有L1 和 L2,但是L3都是共用的。

CPU在读取数据时, 先在L1中寻找, 再从L2中寻找, 再从L3中寻找, 然后是内存, 最后是外存储器。

上边主要是了解一些概念就可以了。

  • ③ 缓存同步协议

多CPU读取同样的数据进行缓存。多个CPU读取同样的数据,修改同样的数据,首先数据体验在缓存上面,最终写入主内存以哪个CPU为准?如果有4个CPU,都对一个 i 进行修改,都体现在自己的L1 一级缓存里面,我们需要将缓存数据写入到内存里面,在这种高速缓存回写的场景下,有一个缓存一致性协议多数CPU厂家对它进行了实现,也就是多个CPU厂家一起定义了一个协议。

每个缓存都必须有个状态位,目前定义了4个状态位。

1.修改态(Modified),此cache行已被修改过(脏行),内容已不同于主存,为此cache专有。 2.专有态(Exclusive),此cache行内容同于主存,但不出现于其他cache中。 3.共享态(Shared),此cache行内容同于主存,但也出现于其他cache中。 4.无效态(Invalid),此cache行内容无效,需要从主内存重新加载。

MESI协议:多处理器时,单个CPU对缓存中数据进行了改动,需要通知给其他CPU,也就是意味着,CPU处理要控制自己的读写操作,还要监听其中他CPU发出来的通知,从而保证最终一致。不仅自己干活,还要看看别人干了什么事情。

  • ④ 运行时指令重排

指令重排是指在程序执行过程中, 为了性能考虑, 编译器和CPU可能会对指令重新排序。可能将后面的读缓存命令有限执行。

//代码
int x  = 10;
int y = z;

正常执行的三步骤 1.将10写入x 2.读取z的值 3.将z值写入y

指令重排后执行 1.读取z的值 2.将z值写入y 3.将10写入x

指令重排并非随意的,需要最受as-if-serial语义 不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守as-if-serial语义。不会对存在数据依赖关系的操作做重排序。 分析:关键词是单线程情况下,必须遵守;其余的不遵守。

  • ⑤ CPU高速缓存和CPU执行指令重排序的问题

1.缓存中的数据与主内存的数据并不是实时同步的, 各CPU间缓存的数据也不是实时同步. 在同一时间点, 各CPU所看到的同一内存地址的数据的值可能是不一致的。 2.虽然遵守了as-if-serial语义, 但仅在单CPU自己执行的情况下能保证结果正确. 多核多线程中, 指令逻辑无法分辨因果关联, 可能出现乱序执行, 导致程序运行结果错误。

  • ⑥ 解决CPU告诉缓存和CPU质量重排序的问题

1.写内存屏障(Store Memory Barrier): 在指令后插入Store Barrier, 能让写入缓存中的最新数据更新写入主内存, 让其他线程可见强制写入主内存, 这种显示调用, CPU就不会因为性能考虑而进行指令重排。

2.读内存屏障(Load Memory Barrier): 在指令前插入Load Barrier, 可以让高速缓存中的数据失效, 强制从新从主内存读取数据强制读取主内存内容, 让CPU缓存和主内存保持一致, 避免了缓存导致的一致性问题。

PS:本节主要是为后面的JVM线程安全问题做个铺垫。同时也看到了现代CPU不断的严禁,在程序运行优化中做出的努力。不同CPU厂家付出的人力物力成本,最终体现在不同的CPU性能差距上。同样是做cpu,有的可以跑lol手游,有的只能玩贪吃蛇,这就是性能的区别。

本文分享自微信公众号 - 编程坑太多(idig88)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 『互联网架构』软件架构-netty之websocket协议应用实践(59)

    为了解决上述弊端,Html5定义了WebSocket协义能更好的节省服务器资源和宽带达到实时通信的目的。

    IT故事会
  • 数据结构与算法—选择排序(Java实现)

    IT故事会
  • 『互联网架构』软件架构-git服务搭建与使用(四)

    很多跟我一样大概有十多年的同事,一直做着企业内部开发,现在还在使用svn,跟大家聊起来git,他们都知道,只是项目里用习惯了svn一直也没改变,我相信这只是时间...

    IT故事会
  • 原来 CPU 为程序性能优化做了这么多

    本文主要来学习内存屏障和 CPU 缓存知识,以便于我们去了解 CPU 对程序性能优化做了哪些努力。

    武培轩
  • CPU缓存和内存屏障

    为了提高程序的运行性能, 现代CPU在很多方面对程序进行了优化 例如: CPU高速缓存, 尽可能的避免处理器访问主内存的时间开销, 处理器大多会利用缓存以提高性...

    CodingDiray
  • 就是要你懂 Java 中 volatile 关键字实现原理

    我们知道volatile关键字的作用是保证变量在多线程之间的可见性,它是java.util.concurrent包的核心,没有volatile就没有这么多的并发...

    哲洛不闹
  • CAS指令与MESI缓存一致性协议、 “轻量级锁” 与原子操作CAS指令与MESI缓存一致性协议、 “轻量级锁” 与原子操作

    CAS指令,在Intel CPU上称为CMPXCHG。最常见的原子操作有Compare and Exchange,Self Increase/Decrease等...

    一个会写诗的程序员
  • Linux监控系统相关资源和运行状态命令整理

    #前言:Linux系统自带了些实时查看监控系统运行状态的相关命令,接下来我们就来了解一下。

    guoke-boy
  • gradle项目中如何支持java与scala混合使用?

    24-丰总
  • 标题党:第一次接触区块链技术,竟然是这种方式

    大神带我来搬砖

扫码关注云+社区

领取腾讯云代金券