赞
踩
《编码:隐匿在计算机硬件背后的语言》
语言:C java 《C程序设计语言》《C primer Plus》
数据结构与算法:《java数据结构与算法》 《算法》 《算法导论》 《计算机程序设计艺术》
操作系统:Linux内核源码详解 30天自制操作系统
网络:机工《TCP/IP详解》卷一
编译原理: 机工 龙书《编译原理》 编程语言实现模式
数据库: SQLite源码 derby
计算机需要解决的最根本的问题,就是怎么代表数字
cpu的制作过程,cpu的原理:晶体管的工作原理《编码》17章
01001000 为了好记这段代码 比如这段代码表示:add
汇编的本质:助记符(可以理解为词典,将二进制编码翻译成我们可读的信息)。就是通过表来翻译二进制编码,本质就是机器语言。
计算机通电-》CPU读取内存中程序(电信号输入) -》 时针发生器不断震荡通断电 -》 推动CPU内部一步一步执行(执行多少步取决于指令需要多少的时钟周期)-》计算完成-》写回(电信号)-》DMA写给显卡输出(显卡内部有缓冲区,每个缓冲区的位置都对应屏幕的位置)
时针发生器的震动频率就是计算机主频
问题:java的解释与编译的区别?
java编译后是Bytecode二进制码,通过jvm的解释器解释为cpu的机器语言(解释执行)。c语言编译后放入内存即为机器语言,可以直接cpu执行。
cpu的二进制语言即机器语言与java语言的bytecode二进制语言有什么区别?
java为了跨平台,bytecode是java自身的二进制语言,需要jvm跟据不同的操作系统,跟据不同系统的解释器,解释为相应操作系统的机器语言,去cpu执行(跨平台原理)。
cpu和内存是计算机硬件核心。
cpu的基本组成:
PC->programme Counter 程序计数器 : 记录当前指令地址。内存是个特别大的数组,当前指令在内存的哪个位置,需要记录指令的地址。
Registers 寄存器 :暂时存储CPU计算机需要用到的数据(从内存内拷贝临时数据到CPU内部,便于指令执行,运行计算完指令释放), 寄存器好几个,各个都有各自的功能。与JVM的栈有相似点。成本很高。
64位CPU表示寄存器可以一次存储64的数字,ALU可以一次读64位数字。
ALU:Arithmetic & LOgicUnit 运算单元,做计算机运算。 如 内存内有两个数字 2,3,求和
运算流程为:内存中的数字2copy到寄存器A,3copy到寄存器B。程序计数器PC记录当前指令为Add。
ALU接收到Add命令,会到A和B取出2,3进行计算,计算完成后输出给寄存器C,最后C再将结果copy到内存的某个位置。
CU :Control UNit 控制单元
MMU : memory management unit 内存管理单元。硬件加操作系统组成。
cache : 缓存
超线程:
一个运算单元对应多个pc和寄存器。如果不对应多个,需要线程切换。如三个线程ABC,CPU只有一个PC和寄存器,则线程A执行,执行过程中,数据暂存,切换到B线程执行B线程,这样的切换就是线程切换,上下文切换,context switch。效率比较低。
如果CPU比较强,可以有很多个PC,寄存器,线程能更快的切换。
缓存的物理结构:
每个CPU内有两个核,每个核都有L1,L2,两个核共享L3.
如果有两个CPU,则两个CPU共享内存。如图:
缓存原理:按块读取:跟据程序局部性原理,读取同时可以读取附近的数据,可以提高效率。
充分发挥总线CPU针脚等一次性读取更多数据的能力。
cacleline的概念:缓存行
主内存的数据-》L3 -》L2-》L1-》计算单元与寄存器
CPU内部的缓存一致性协议MESI,是以缓存行为单位的。
如:
CPU A的L2的缓存发生变动,则计算机的其它CPU的L2也要同样更新变动,重新从内存读取。
有的数据一个缓存行装不下。缓存行不适合,保持一致性需要锁总线。缓存一致性协议有时也被成为缓存锁。终极解决方案就是锁总线,只能当前缓存行读取完,其它CPU才能访问内存。
缓存行越大,局部性空间效率越高,但读取时间慢。
缓存行越小,局部性空间效率越低,但读取时间快。
英特尔折中,一行64字节。
伪共享:
在多核架构中, 会发生一种伪共享的情况,原因是,每个cpu缓存自己的数据,cpu0对long i进行操作,缓存了i和i附近共计64字节数据;cpu1对long j进行操作,缓存了j和j附近共计64字节的数据。若i和j相邻,那么两个cpu缓存的就是主存中相同的一段64字节的内存数据。此时若cpu0对i的操作是写,导致这段地址上的数据对于其他cpu的缓存失效,cpu1尽管不操作i,也需要重新去主存中load这段数据,导致了额外的开销
由于缓存一致性协议会造成不同CPU之间的相同缓存行不停的更新,会造成性能降低。
案例:一:已知long类型长度为8,则在一个long类型的数组长度为2,分成两个线程,分别不停的更新数组的两个位置,即A线程更新index0位置,B线程更新index1。
二:long数组设置为长度为16,即总长度为128,A线程更新index0位置,B线程更新index8位置。
会发现第二种方案会比第一种方案效率更高。
已知英特尔的缓存行长度为64
因为第一个方案,两个线程的更新一直是一个缓存行,触发缓存一致性协议,影响效率。而第二个方案,由于index8超出了64长度,因此index0与index8不在同一个缓存行,所以效率更高。
缓存行对齐:
对于有些特别敏感的数字,会存在线程高竞争的访问,为了保证不发生伪共享,可以使用缓存行对齐的编程方式。
JDK7中采用long padding提高效率,即加入两个长度为8的long数组。
JDK8中,加入了@Contended注解,配合 JVM: -XX:-Restrictcontended 实现缓存行对齐
CPU的乱序执行
两个互相没有关联的指令会乱序执行。
代码:jvm/jmm/Disord.java
乱序执行会出现的问题:
DCL (Double check Lock) 双重锁单例为什么是单例volitle?到底需要不需要volatile
由于初始化的过程中分为很多指令,存在中间态。
由于CPU的乱序执行,有可能发生指令重排序:
问题:如何解决指令重排序?
1.设置内存屏障
对某部分内存做操作时前后添加的屏障,屏障前后的操作不可以乱序执行。.
intel CPU层面硬件实现 有三个原语:lfence(读屏障) sfence(写屏障) mfence(读写屏障)
也可以使用总线锁来解决cpu指令重排序的问题。
2.有序性保障也可以通过 intel lock汇编指令实现。lock指令又为原子指令。指令是一个Full Barrier,执行时会锁住内存子系统来保证执行顺序,甚至跨多个CPU。Software Locks通常使用了内存屏障或原子指令来实现变量可见性和保持程序顺序。
3.JVM层级的内存屏障,与硬件没有任何关系。 SS,SL,LL,LS (s:store 写 l:load 读)
volatile的实现细节,即在volatile前后加了jvm的内存屏障。
:Jvm层面
CPU指令重排序规则:只要前后两条指令没有互相依赖的关系,即可重排序乱序执行。
JMV指令重排序规则:Hanppens-before原则 JLS - java language sepicifation 8条规则
- 程序次序规则:在一个线程内一段代码的执行结果是有序的。就是还会指令重排,但是随便它怎么排,结果是按照我们代码的顺序生成的不会变!
- 管程锁定规则:就是无论是在单线程环境还是多线程环境,对于同一个锁来说,一个线程对这个锁解锁之后,另一个线程获取了这个锁都能看到前一个线程的操作结果!(管程是一种通用的同步原语,synchronized就是管程的实现)
- volatile变量规则:就是如果一个线程先去写一个volatile变量,然后一个线程去读这个变量,那么这个写操作的结果一定对读的这个线程可见。
- 线程启动规则:在主线程A执行过程中,启动子线程B,那么线程A在启动子线程B之前对共享变量的修改结果对线程B可见。
- 线程终止规则:在主线程A执行过程中,子线程B终止,那么线程B在终止之前对共享变量的修改结果在线程A中可见。
- 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生,可以通过Thread.interrupted()检测到是否发生中断。
- 传递规则:这个简单的,就是happens-before原则具有传递性,即A happens-before B , B happens-before C,那么A happens-before C。
- 对象终结规则:这个也简单的,就是一个对象的初始化的完成,也就是构造函数执行的结束一定 happens-before它的finalize()方法。
as if serial 不管如何重排序,单线程执行结果不会改变。
总结:解决CPU指令重排序方法?
CPU层面:三个原语:Lfence, Sfence, MFence 或者lock指令锁总线。
JVM层级:8个happens-before原则 + 4个内存屏障 (LL,LS, SS, SL)
as-if-serial:不管硬件什么顺序,单线程执行的结果不变,看上去像是serial
扩展问题:多个请求,要求顺序执行,怎么操作?
为了提高写效率,cpu在写入L1时,同时用wc写入L2
计算单元,寄存器与L1之间还有一个缓存单元叫:storeBuffer,空间特别小。
满四个字节,通过wc直接写入L2
由于ALU速度太快,所以在写入L1的同时,写入一个wcBuffer即storebuffer,满了之后直接写入L2
UMA,多个CPU共享一块儿内存空间 :一致性内存访问
一致性内存访问缺点:不宜扩展,cpu数量增多后引起内存访问冲突加剧。cpu的很多资源花在争抢内存地址上面。4颗CPU左右比较合适。
NUMA:指在主板插槽上,一组CPU有一个专用的memory内存。各组CPU与内存通过总线连接,也可以总线互相访问别的cpu的专用内存(效率较低) 就近访问原则。
ZGC-NUMA-aware 最近内存分配
分配内存会优先分配该线程所在CPU的最近内存
通电->biod uefi工作 ->自检 -》到硬盘固定位置加载bootloader-》读取可配置信息-》可配置信息存放于cmos
bootloader将读取到的相应的操作系统内核配置信息,读入计算机内存。
然后计算机权限交给操作系统内核。-OS
os本身就是一个软件,可以同时管理硬件(cpu,内存等)和应用(进程)
linux操作系统:《linux内核设计与实践》
内核:
宏内核:所有的功能都具备。这些功能程序都与内核在一块儿内存空间或者说芯片(计算机内存)
微内核:应用管理进程调度。只有进程调度与微内核在一块儿内存空间。因此微内核操作文件系统可以理解为:本身没有读硬盘的程序,需要到其它空间或芯片找到文件系统功能(可通过互联网或局域网),读完后返回给内核,内核在返回给应用。(效率低,弹性部署 5G loT)
鸿蒙即基于微内核,弹性部署,通过互联网实现微内核互联。
各设备都有各自功能的微内核,各设备通过互联网实现互联,可以实现以下功能:
冰箱:洗碗机,把我里面的碗洗一下。
洗碗机:ok没问题,机器人,去冰箱把碗拿给我。
机器人:ok没问题
外核:存在于科研实验室(不重要)为应用定制操作系统(多租户 request-based GC JVM定制化)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。