日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java程序员需要掌握的计算机底层知识(一):CPU基本组成、指令乱序执行、合并写技术、非同一访问内存 NUMA

發布時間:2024/2/28 java 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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);} } // 輸出:1163

T02_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 的亂序執行

亂序執行的意思,實際上是在同時執行。本質上是在提高效率。

一個小例子,證明亂序的存在:

package com.mashibing.jvm.c3_jmm;public class T04_Disorder {private static int x = 0, y = 0;private static int a = 0, b =0;public static void main(String[] args) throws InterruptedException {int i = 0;for(;;) {i++;x = 0; y = 0;a = 0; b = 0;Thread one = new Thread(new Runnable() {public void run() {//由于線程one先啟動,下面這句話讓它等一等線程two. 讀著可根據自己電腦的實際性能適當調整等待時間.//shortWait(100000);a = 1;x = b;}});Thread other = new Thread(new Runnable() {public void run() {b = 1;y = a;}});one.start();other.start();one.join();other.join();String result = "第" + i + "次 (" + x + "," + y + ")";if(x == 0 && y == 0) {System.err.println(result);break;} else {//System.out.println(result);}}}public static void shortWait(long interval){long start = System.nanoTime();long end;do{end = System.nanoTime();}while(start + interval >= end);} }

執行結果:出現了 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 的存在:

package com.mashibing.juc.c_029_WriteCombining;public final class WriteCombining {private static final int ITERATIONS = Integer.MAX_VALUE;private static final int ITEMS = 1 << 24;private static final int MASK = ITEMS - 1;private static final byte[] arrayA = new byte[ITEMS];private static final byte[] arrayB = new byte[ITEMS];private static final byte[] arrayC = new byte[ITEMS];private static final byte[] arrayD = new byte[ITEMS];private static final byte[] arrayE = new byte[ITEMS];private static final byte[] arrayF = new byte[ITEMS];public static void main(final String[] args) {for (int i = 1; i <= 3; i++) {System.out.println(i + " SingleLoop duration (ns) = " + runCaseOne());System.out.println(i + " SplitLoop duration (ns) = " + runCaseTwo());}}public static long runCaseOne() {long start = System.nanoTime();int i = ITERATIONS;while (--i != 0) {int slot = i & MASK;byte b = (byte) i;arrayA[slot] = b;arrayB[slot] = b;arrayC[slot] = b;arrayD[slot] = b;arrayE[slot] = b;arrayF[slot] = b;}return System.nanoTime() - start;}public static long runCaseTwo() { // 一次正好寫滿一個四字節的 Buffer,比上面的循環效率更高long start = System.nanoTime();int i = ITERATIONS;while (--i != 0) {int slot = i & MASK;byte b = (byte) i;arrayA[slot] = b;arrayB[slot] = b;arrayC[slot] = b;}i = ITERATIONS;while (--i != 0) {int slot = i & MASK;byte b = (byte) i;arrayD[slot] = b;arrayE[slot] = b;arrayF[slot] = b;}return System.nanoTime() - start;} }

非同一訪問內存 NUMA

UMA:同一內存訪問。多個CPU通過一條總線,訪問同一個內存。
現在很多服務器的架構是使用NUMA的,因為UMA不以拓展:隨著CPU的數量增多,許多時間被浪費在CPU爭搶內存資源上。

NUMA:非同一訪問內存。每個CPU有自己專屬的內存,CPU對于自己插槽上的內存訪問是有優先級的。

ZGC 可以做到 NUMA aware,如果探測到計算機實現了NUMA的話,分配內存會優先分配該線程所在CPU的最近內存。

總結

以上是生活随笔為你收集整理的Java程序员需要掌握的计算机底层知识(一):CPU基本组成、指令乱序执行、合并写技术、非同一访问内存 NUMA的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。