前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >操作系统篇-cpu

操作系统篇-cpu

作者头像
lovelife110
发布2021-01-14 16:24:04
3360
发布2021-01-14 16:24:04
举报

以下针对java说明

汇编语言(机器语言)的执行过程

计算机通电 -> CPU读取内存中程序(电信号输入)->时钟发生器不断震荡通断电 ->推动CPU内部一步一步执行(执行多少步取决于指令需要的时钟周期)->计算完成->写回(电信号)->写给显卡输出(sout,或者图形)

cpu为什么需要时钟发生器: 时钟是为了同步CPU中各种门电路。

超线程

在这里插入图片描述
在这里插入图片描述

四核八线程 其实就是一个ALU对应2个寄存器(registers),平时在读取数据的时候,就会把一个线程相关的数据存储在寄存器里,指令地址存储在PC里面,之后ALU对数据进行计算,如果CPU时间片到了切换线程的时候,就可以把寄存器直接切换到下一个寄存器里进行下一个数据的运算。而不用像只有一个寄存器的时候,在切换线程的时候,需要先把当前寄存器的数据存回内存。

CPU缓存的结构

下图2个cpu,1个cpu2核

在这里插入图片描述
在这里插入图片描述

L3有的也有在主板上,离cpu很近

缓存行

在读取数据的时候是按块读取,这些块,在缓存的领域被称作缓存行 程序局部性原理,可以提高效率 充分发挥总线CPU针脚等一次性读取更多数据的能力

缓存行越大,局部性空间效率越高,但读取时间慢 缓存行越小,局部性空间效率越低,但读取时间快 取一个折中值,目前多用:64字节

缓存一致性协议

读取数据会先把数据读到缓存行,如果有一个数据同时被两个线程访问,其中一个cpu修改了数据,这个时候会触发MESI Cache数据一致性协议(intel cpu),会使另一个线程的缓存行失效,另一个数据会从新从内存中读取新的数据。 简单的讲,就是给缓存行标记四种状态,分别是Modified(被修改)、Exclusive(独享的)、Shared(共享的)、Invalid(失效的)。根据不同的状态进行操作达成数据的一致性。 但是有的数据,一个缓存行无法装下,这个时候如果要保持数据一致性,需要锁总线。 跨多个缓存行的数据必须使用总线锁

在这里插入图片描述
在这里插入图片描述

缓存行对齐

缓存行对齐:对于有些特别敏感的数字,会存在线程高竞争的访问,为了保证不发生伪共享(多个线程同时读取到了同一缓存行时,为了使线程之间的可见性,会使用volatile关键字,使其他线程的缓存行失效进而从内存中从新读取数据,进而造成性能的降低),可以使用缓存行对齐的编程方式

JDK7中,很多采用long padding提高效率

JDK8,加入了@Contended注解,需要加上:JVM -XX:-RestrictContended

开源项目例子:disruptor 高性能并发队列 java 一个long 8个字节,p1~p7加上插入的一个p,就是64字节,对应一个缓存行

在这里插入图片描述
在这里插入图片描述

乱序执行

CPU在进行读等待的同时执行其他指令,是CPU乱序的根源,不是乱,而是提高效率。

乱序执行可能会产生的问题

经典例子:DCL(Double Check Lock)单例为什么要加volative?

public class Singleton {
	// 加volatile禁止指令重排序
    private volatile Singleton singleton;
    // 构造函数是private,防止外部实例化
    private Singleton() {}
    public static Singleton getInstance() {
        if (singleton == null) { // 第一次检查
            synchronized (Singleton.class) {
                if (singleton == null) { // 第二次检查,"double check"的由来
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
在这里插入图片描述
在这里插入图片描述

new指令不是原子: new的时候只是在内存申请一个空间并在栈顶压入了指向这段内存的地址(即引用),只有执行完invokespecial后才把m赋值为8。 dup,即 duplicate,其作用就是复制之前分配的new 空间的引用并压入栈顶,为什么需要这个是因为invokespecial 通过#3这个常量池入口找到构造方法,需要知道是谁的构造方法,所以需要消耗一个引用才能执行构造方法,然后弹出栈。 astore_1:调用astore_1将此时的栈顶值弹出存入局部变量中第1的位置(第0位置是this)。

所以,在new一半的时候,可能会发生指令重排,所以DCL(Double Check Lock)单例要加volative

在这里插入图片描述
在这里插入图片描述

CPU层面如何禁止乱序?

内存屏障 对某部分内存做操作时前后添加屏障,屏障前后的操作时不可以乱序执行的。

在这里插入图片描述
在这里插入图片描述

Intel cpu 底层实现:原语,汇编指令(mfence lfence sfence) 或者总线锁

sfence,写屏障,在sfence指令前的写操作当必须在sfence指令后写操作前完成。 lfence,读屏障,在lfence指令前的读操作当必须在lfence指令后的读操作之前完成。 mfence,读写屏障,在mfence执行之前的读写操作必须在mfence指令后的读写操作之前完成。

intel lock指令 是一个Full Barrier,执行时会锁住内存子系统来确保执行顺序,甚至跨多个cpu。

JVM规范禁止乱序

JSR内存屏障:

在这里插入图片描述
在这里插入图片描述

以下是JVM规范volatile实现,但是在hotspot里,是通过 lock addl $0x0,(%rsp)实现。

StoreStoreBarrier //写写屏障 volatile 写操作 StoreLoadBarrier //写读屏障

LoadLoadBarrier volatile读操作 LoadStoreBarrier

8个hanppens-before原则:

在这里插入图片描述
在这里插入图片描述

as-if-serial : 不管硬件什么顺序,单线程执行的结果不变,看上去像是按顺序。 比如在一个单线程里面 x=1 y=2 换为 y=2 x=1 单线程执行的结果不变,看上去就像是按顺序执行。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-10-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 汇编语言(机器语言)的执行过程
  • 超线程
  • CPU缓存的结构
  • 缓存行
  • 缓存一致性协议
  • 缓存行对齐
  • 乱序执行
  • 乱序执行可能会产生的问题
  • CPU层面如何禁止乱序?
  • JVM规范禁止乱序
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档