Java程序员需要掌握的计算机底层知识(一):CPU基本组成、指令乱序执行、合并写技术、非同一访问内存 NUMA
一些書籍
讀書的原則:不求甚解,觀其大略
你如果進到廬山里頭,二話不說,蹲下頭來,彎下腰,就對著某棵樹某棵小草猛研究而不是說先把廬山的整體脈絡跟那研究清楚了,那么你的學習方法肯定效率巨低而且特別痛苦,最重要的還是慢慢地還打擊你的積極性,說我的學習怎么那么不happy啊,怎么那么特沒勁那,因為你的學習方法錯了,大體讀明白,先拿來用,用著用著,很多道理你就明白了
?《編碼:隱匿在計算機軟硬件背后的語言》
?《深入理解計算機系統》
?語言:C JAVA K&R《C程序設計語言》《C Primer Plus》
? 數據結構與算法: – 畢生的學習 leetCode
–《Java數據結構與算法》《算法》
–《算法導論》《計算機程序設計藝術》//難
?操作系統:Linux內核源碼解析 Linux內核設計與實現 30天自制操作系統
?網絡:機工《TCP/IP詳解》卷一 翻譯一般
?編譯原理:機工 龍書 《編譯原理》 《編程語言實現模式》馬語
?數據庫:SQLite源碼 Derby - JDK自帶數據庫
硬件基礎知識
CPU的制作過程
Intel cpu的制作過程
https://haokan.baidu.com/v?vid=11928468945249380709&pd=bjh&fr=bjhauthor&type=video
CPU是如何制作的(文字描述)
https://www.sohu.com/a/255397866_468626
匯編語言(機器語言)的執行過程
匯編語言的本質:機器語言的助記符 其實它就是機器語言
計算機通電 -> CPU讀取內存中程序(電信號輸入)
->時鐘發生器不斷震蕩通斷電 ->推動CPU內部一步一步執行
(執行多少步取決于指令需要的時鐘周期)
->計算完成->寫回(電信號)->寫給顯卡輸出(sout,或者圖形)
量子計算機
量子比特,同時表示1 0
CPU的基本組成
PC -> Program Counter 程序計數器 (記錄當前指令地址)
Registers -> 暫時存儲CPU計算需要用到的數據
ALU -> Arithmetic & Logic Unit 運算單元
CU -> Control Unit 控制單元
MMU -> Memory Management Unit 內存管理單元
Java相關硬件知識
cache 緩存
一致性協議:https://www.cnblogs.com/z00377750/p/9180644.html
緩存行:
緩存行越大,局部性空間效率越高,但讀取時間慢
緩存行越小,局部性空間效率越低,但讀取時間快
取一個折中值,目前多用:64字節
證明緩存行的存在:
T01_CacheLinePadding.java
package com.mashibing.juc.c_028_FalseSharing;import java.util.Random;public class T01_CacheLinePadding {private static class T {public volatile long x = 0L;}public static T[] arr = new T[2];static {arr[0] = new T();arr[1] = new T();}public static void main(String[] args) throws Exception {Thread t1 = new Thread(()->{for (long i = 0; i < 1000_0000L; i++) {arr[0].x = i;}});Thread t2 = new Thread(()->{for (long i = 0; i < 1000_0000L; i++) {arr[1].x = i;}});final long start = System.nanoTime();t1.start();t2.start();t1.join();t2.join();System.out.println((System.nanoTime() - start)/100_0000);} } // 輸出:1163T02_CacheLinePadding.java
package com.mashibing.juc.c_028_FalseSharing;public class T02_CacheLinePadding {private static class Padding {public volatile long p1, p2, p3, p4, p5, p6, p7;}private static class T extends Padding {public volatile long x = 0L;}public static T[] arr = new T[2];static {arr[0] = new T();arr[1] = new T();}public static void main(String[] args) throws Exception {Thread t1 = new Thread(()->{for (long i = 0; i < 1000_0000L; i++) {arr[0].x = i;}});Thread t2 = new Thread(()->{for (long i = 0; i < 1000_0000L; i++) {arr[1].x = i;}});final long start = System.nanoTime();t1.start();t2.start();t1.join();t2.join();System.out.println((System.nanoTime() - start)/100_0000);} } // 輸出:548以上兩個小例子證明了緩存行的存在。
緩存行對齊:對于有些特別敏感的數字,會存在線程高競爭的訪問,為了保證不發生偽共享,可以使用緩存航對齊的編程方式
JDK7中,很多采用long padding提高效率
JDK8,加入了@Contended注解(實驗)需要加上:JVM -XX:-RestrictContended
CPU 的亂序執行
亂序執行的意思,實際上是在同時執行。本質上是在提高效率。
一個小例子,證明亂序的存在:
執行結果:出現了 0,0,證明了亂序的存在
上面這個小例子來源于外國人寫的一個博客:
https://preshing.com/20120515/memory-reordering-caught-in-the-act/
亂序可能存在的問題:
如何禁止亂序
CPU層面:
(1)使用原語
Intel CPU 的實現方式是,使用原語(匯編指令mfence lfence sfence 或者鎖總線(都屬于硬件實現)
(2)Intel lock 匯編指令
JVM層面
因為不是所有的CPU都有匯編指令的實現,因此JVM在實現的時候使用的是lock指令。
JVM層級:8個hanppens-before原則、4個內存屏障 (LL LS SL SS)
名詞as-if-serial 的含義: 不管硬件什么順序,單線程執行的結果不變,看上去就像是順序執行的一樣。
拓展:很多請求打進來,如果想要順序執行,可以使用SingleThreadPool。為了避免內存溢出,有界隊列滿了可以采取拒絕策略 。
JVM在寫操作和讀操作前后都加了屏障。而屏障的實現,就是使用lock指令。
合并寫技術 Write Combining
寄存器和L1緩存之間還有一個buffer,空間特別小。另外還有一個WC(Write Combining)Buffer,一般是4個字節
由于ALU速度太快,所以在寫入L1的同時,寫入一個WC Buffer,滿了之后,寫滿4個字節之后,才會一次性刷到緩存L2里。可以用程序證明。
證明 WC 的存在:
非同一訪問內存 NUMA
UMA:同一內存訪問。多個CPU通過一條總線,訪問同一個內存。
現在很多服務器的架構是使用NUMA的,因為UMA不以拓展:隨著CPU的數量增多,許多時間被浪費在CPU爭搶內存資源上。
NUMA:非同一訪問內存。每個CPU有自己專屬的內存,CPU對于自己插槽上的內存訪問是有優先級的。
ZGC 可以做到 NUMA aware,如果探測到計算機實現了NUMA的話,分配內存會優先分配該線程所在CPU的最近內存。
總結
以上是生活随笔為你收集整理的Java程序员需要掌握的计算机底层知识(一):CPU基本组成、指令乱序执行、合并写技术、非同一访问内存 NUMA的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 生产环境中,如何防止服务器秘钥被盗取?
- 下一篇: Java程序员需要掌握的计算机底层知识(