主頁 >  其他 > java核心知識點總結篇-JVM篇

java核心知識點總結篇-JVM篇

2021-11-07 07:19:11 其他

2. JVM

(1) 基本概念:

JVM 是可運行 Java 代碼的假想計算機 ,包括一套位元組碼指令集、一組暫存器、一個堆疊、

一個垃圾回收,堆 和 一個存盤方法域,JVM 是運行在作業系統之上的,它與硬體沒有直接

的互動,

(2) 運行程序:

我們都知道 Java 源檔案,通過編譯器,能夠生產相應的.Class 檔案,也就是位元組碼檔案,

而位元組碼檔案又通過 Java 虛擬機中的解釋器,編譯成特定機器上的機器碼 ,

也就是如下:

① Java 源檔案—->編譯器—->位元組碼檔案

② 位元組碼檔案—->JVM—->機器碼

每一種平臺的解釋器是不同的,但是實作的虛擬機是相同的,這也就是 Java 為什么能夠

跨平臺的原因了 ,當一個程式從開始運行,這時虛擬機就開始實體化了,多個程式啟動就會

存在多個虛擬機實體,程式退出或者關閉,則虛擬機實體消亡,多個虛擬機實體之間資料不

能共享,

2.1.**執行緒**

這里所說的執行緒指程式執行程序中的一個執行緒物體,JVM 允許一個應用并發執行多個執行緒,

Hotspot JVM 中的 Java 執行緒與原生作業系統執行緒有直接的映射關系,當執行緒本地存盤、緩

沖區分配、同步物件、堆疊、程式計數器等準備好以后,就會創建一個作業系統原生執行緒,

Java 執行緒結束,原生執行緒隨之被回收,作業系統負責調度所有執行緒,并把它們分配到任何可

用的 CPU 上,當原生執行緒初始化完畢,就會呼叫 Java 執行緒的 run() 方法,當執行緒結束時,

會釋放原生執行緒和 Java 執行緒的所有資源,

Hotspot JVM 后臺運行的系統執行緒主要有下面幾個:

1、虛擬機執行緒(VM thread)

這個執行緒等待 JVM 到達安全點操作出現,這些操作必須要在獨立的執行緒里執行,因為當

堆修改無法進行時,執行緒都需要 JVM 位于安全點,這些操作的型別有:stop-the

world 垃圾回收、執行緒堆疊 dump、執行緒暫停、執行緒偏向鎖(biased locking)解除,

2、周期性任務執行緒

這執行緒負責定時器事件(也就是中斷),用來調度周期性操作的執行,

3、GC 執行緒

這些執行緒支持 JVM 中不同的垃圾回識訓動,

4、編譯器執行緒

這些執行緒在運行時將位元組碼動態編譯成本地平臺相關的機器碼,

5、信號分發執行緒

這個執行緒接收發送到 JVM 的信號并呼叫適當的 JVM 方法處理,

2.2.JVM 記憶體區域

JVM 記憶體區域主要分為執行緒私有區域【程式計數器、虛擬機堆疊、本地方法區】、執行緒共享區

域【JAVA 堆、方法區】、直接記憶體,

執行緒私有資料區域生命周期與執行緒相同, 依賴用戶執行緒的啟動/結束 而 創建/銷毀(在 Hotspot

VM 內, 每個執行緒都與作業系統的本地執行緒直接映射, 因此這部分記憶體區域的存/否跟隨本地執行緒的

生/死對應),

執行緒共享區域隨虛擬機的啟動/關閉而創建/銷毀,

直接記憶體并不是 JVM 運行時資料區的一部分, 但也會被頻繁的使用: 在 JDK 1.4 引入的 NIO 提

供了基于 Channel 與 Buffer 的 IO 方式, 它可以使用 Native 函式庫直接分配堆外記憶體, 然后使用

DirectByteBuffer 物件作為這塊記憶體的參考進行操作(詳見: Java I/O 擴展), 這樣就避免了在 Java

堆和 Native 堆中來回復制資料, 因此在一些場景中可以顯著提高性能,

2.2.1. 程式計數器**(執行緒私有)**

一塊較小的記憶體空間, 是當前執行緒所執行的位元組碼的行號指示器,每條執行緒都要有一個獨立的

程式計數器,這類記憶體也稱為“執行緒私有”的記憶體,

正在執行 java 方法的話,計數器記錄的是虛擬機位元組碼指令的地址(當前指令的地址),如

果還是 Native 方法,則為空,

這個記憶體區域是唯一一個在虛擬機中沒有規定任何 OutOfMemoryError 情況的區域,

2.2.2. 虛擬機堆疊**(執行緒私有)**

是描述java方法執行的記憶體模型,每個方法在執行的同時都會創建一個堆疊幀(Stack Frame)

用于存盤區域變數表、運算元堆疊、動態鏈接、方法出口等資訊,每一個方法從呼叫直至執行完成

的程序,就對應著一個堆疊幀在虛擬機堆疊中入堆疊到出堆疊的程序,

堆疊幀( Frame)是用來存盤資料和部分程序結果的資料結構,同時也被用來處理動態鏈接

(Dynamic Linking)、 方法回傳值和例外分派( Dispatch Exception),堆疊幀隨著方法呼叫而創

建,隨著方法結束而銷毀——無論方法是正常完成還是例外完成(拋出了在方法內未被捕獲的異

常)都算作方法結束,

2.2.3. 本地方法區**(執行緒私有)**

本地方法區和 Java Stack 作用類似, 區別是虛擬機堆疊為執行 Java 方法服務, 而本地方法堆疊則為

Native 方法服務, 如果一個 VM 實作使用 C-linkage 模型來支持 Native 呼叫, 那么該堆疊將會是一個

C 堆疊,但 HotSpot VM 直接就把本地方法堆疊和虛擬機堆疊合二為一,

2.2.4. 堆(**Heap-執行緒共享)-運行時資料區**

是被執行緒共享的一塊記憶體區域,創建的物件和陣列都保存在 Java 堆記憶體中,也是垃圾收集器進行

垃圾收集的最重要的記憶體區域,由于現代 VM 采用分代收集演算法, 因此 Java 堆從 GC 的角度還可以

細分為: 新生代(Eden 區From Survivor 區To Survivor 區)和老年代,

2.2.5. 方法區**/永久代(執行緒共享)**

即我們常說的永久代(Permanent Generation), 用于存盤被 JVM 加載的類資訊常量

態變數即時編譯器編譯后的代碼等資料. HotSpot VM把GC分代收集擴展至方法區, 即使用Java

堆的永久代來實作方法區, 這樣 HotSpot 的垃圾收集器就可以像管理 Java 堆一樣管理這部分記憶體,

而不必為方法區開發專門的記憶體管理器(永久帶的記憶體回收的主要目標是針對常量池的回收型別

的卸載, 因此收益一般很小),

運行時常量池(Runtime Constant Pool)是方法區的一部分,Class 檔案中除了有類的版

本、欄位、方法、介面等描述等資訊外,還有一項資訊是常量池(Constant Pool Table),

用于存放編譯期生成的各種字面量和符號參考,這部分內容將在類加

載后存放到方法區的運行時常量池中, Java 虛擬機對 Class 檔案的每一部分(自然也包括常量

池)的格式都有嚴格的規定,每一個位元組用于存盤哪種資料都必須符合規范上的要求,這樣才會

被虛擬機認可、裝載和執行,

2.3.JVM 運行時記憶體

Java 堆從 GC 的角度還可以細分為: 新生代(Eden 區From Survivor 區To Survivor 區)和老年

代,

2.3.1. 新生代

是用來存放新生的物件,一般占據堆的 1/3 空間,由于頻繁創建物件,所以新生代會頻繁觸發

MinorGC 進行垃圾回收,新生代又分為 Eden 區、ServivorFrom、ServivorTo 三個區,

2.3.1.1.

Eden

Java 新物件的出生地(如果新創建的物件占用記憶體很大,則直接分配到老

年代),當 Eden 區記憶體不夠的時候就會觸發 MinorGC,對新生代區進行

一次垃圾回收,

2.3.1.2.

ServivorFrom

上一次 GC 的幸存者,作為這一次 GC 的被掃描者,

2.3.1.3.

ServivorTo

保留了一次 MinorGC 程序中的幸存者,

2.3.1.4. MinorGC 的程序(復制->清空->互換)

MinorGC 采用復制演算法,

1edenservicorFrom 復制到 ServicorTo,年齡+1

首先,把 Eden 和 ServivorFrom 區域中存活的物件復制到 ServicorTo 區域(如果有物件的年

齡以及達到了老年的標準,則賦值到老年代區),同時把這些物件的年齡+1(如果 ServicorTo 不

夠位置了就放到老年區);

2:清空** eden**、servicorFrom**

然后,清空 Eden 和 ServicorFrom 中的物件;

3:ServicorTo** ServicorFrom 互換

最后,ServicorTo 和 ServicorFrom 互換,原 ServicorTo 成為下一次 GC 時的 ServicorFrom

區,

2.3.2. 老年代

主要存放應用程式中生命周期長的記憶體物件,

老年代的物件比較穩定,所以 MajorGC 不會頻繁執行,在進行 MajorGC 前一般都先進行

了一次 MinorGC,使得有新生代的物件晉身入老年代,導致空間不夠用時才觸發,當無法找到足

夠大的連續空間分配給新創建的較大物件時也會提前觸發一次 MajorGC 進行垃圾回收騰出空間,

MajorGC 采用標記清除演算法:首先掃描一次所有老年代,標記出存活的物件,然后回收沒

有標記的物件,MajorGC 的耗時比較長,因為要掃描再回收,MajorGC 會產生記憶體碎片,為了減

少記憶體損耗,我們一般需要進行合并或者標記出來方便下次直接分配,當老年代也滿了裝不下的

時候,就會拋出 OOM(Out of Memory)例外,

2.3.3. 永久代

指記憶體的永久保存區域,主要存放 Class 和 Meta(元資料)的資訊,Class 在被加載的時候被

放入永久區域,它和和存放實體的區域不同,GC 不會在主程式運行期對永久區域進行清理,所以這

也導致了永久代的區域會隨著加載的 Class 的增多而脹滿,最終拋出 OOM 例外,

2.3.3.1. JAVA8 與元資料

在 Java8 中,永久代已經被移除,被一個稱為“元資料區”(元空間)的區域所取代,元空間

的本質和永久代類似,元空間與永久代之間最大的區別在于:元空間并不在虛擬機中,而是使用

本地記憶體,因此,默認情況下,元空間的大小僅受本地記憶體限制,類的元資料放入 native

memory, 字串池和類的靜態變數放入 java 堆中,這樣可以加載多少類的元資料就不再由

MaxPermSize 控制, 而由系統的實際可用空間來控制,

2.4.垃圾回收與演算法

2.4.1. 如何確定垃圾

2.4.1.1.

參考計數法

在 Java 中,參考和物件是有關聯的,如果要操作物件則必須用參考進行,因此,很顯然一個簡單

的辦法是通過參考計數來判斷一個物件是否可以回收,簡單說,即一個物件如果沒有任何與之關

聯的參考,即他們的參考計數都不為 0,則說明物件不太可能再被用到,那么這個物件就是可回收

物件,

2.4.1.2.

可達性分析

為了解決參考計數法的回圈參考問題,Java 使用了可達性分析的方法,通過一系列的“GC roots”

物件作為起點搜索,如果在“GC roots”和一個物件之間沒有可達路徑,則稱該物件是不可達的,

要注意的是,不可達物件不等價于可回收物件,不可達物件變為可回收物件至少要經過兩次標記

程序,兩次標記后仍然是可回收物件,則將面臨回收,

2.4.2. 標記清除演算法(**Mark-Sweep)**

最基礎的垃圾回收演算法,分為兩個階段,標注和清除,標記階段標記出所有需要回收的物件,清

除階段回收被標記的物件所占用的空間,如圖

從圖中我們就可以發現,該演算法最大的問題是記憶體碎片化嚴重,后續可能發生大物件不能找到可

利用空間的問題,

2.4.3. 復制演算法(**copying)**

為了解決 Mark-Sweep 演算法記憶體碎片化的缺陷而被提出的演算法,按記憶體容量將記憶體劃分為等大小

的兩塊,每次只使用其中一塊,當這一塊記憶體滿后將尚存活的物件復制到另一塊上去,把已使用

的記憶體清掉,如圖:

這種演算法雖然實作簡單,記憶體效率高,不易產生碎片,但是最大的問題是可用記憶體被壓縮到了原

本的一半,且存活物件增多的話,Copying 演算法的效率會大大降低,

2.4.4. 標記整理演算法**(Mark-Compact)**

結合了以上兩個演算法,為了避免缺陷而提出,標記階段和 Mark-Sweep 演算法相同,標記后不是清

理物件,而是將存活物件移向記憶體的一端,然后清除端邊界外的物件,如圖:

2.4.5. 分代收集演算法

分代收集法是目前大部分 JVM 所采用的方法,其核心思想是根據物件存活的不同生命周期將記憶體

劃分為不同的域,一般情況下將 GC 堆劃分為老生代(Tenured/Old Generation)和新生代(Young

Generation),老生代的特點是每次垃圾回收時只有少量物件需要被回收,新生代的特點是每次垃

圾回收時都有大量垃圾需要被回收,因此可以根據不同區域選擇不同的演算法,

2.4.5.1. 新生代與復制演算法

目前大部分 JVM 的 GC 對于新生代都采取 Copying 演算法,因為新生代中每次垃圾回收都要

回收大部分物件,即要復制的操作比較少,但通常并不是按照 1:1 來劃分新生代,一般將新生代

劃分為一塊較大的 Eden 空間和兩個較小的 Survivor 空間(From Space, To Space),每次使用

Eden 空間和其中的一塊 Survivor 空間,當進行回收時,將該兩塊空間中還存活的物件復制到另

一塊 Survivor 空間中,

2.4.5.2. 老年代與標記復制演算法

而老年代因為每次只回收少量物件,因而采用 Mark-Compact 演算法,

\1. JAVA 虛擬機提到過的處于方法區的永生代(Permanet Generation),它用來存盤 class 類,

常量,方法描述等,對永生代的回收主要包括廢棄常量和無用的類,

\2. 物件的記憶體分配主要在新生代的 Eden Space 和 Survivor Space 的 From Space(Survivor 目

前存放物件的那一塊),少數情況會直接分配到老生代,

\3. 當新生代的 Eden Space 和 From Space 空間不足時就會發生一次 GC,進行 GC 后,Eden

Space 和 From Space 區的存活物件會被挪到 To Space,然后將 Eden Space 和 From

Space 進行清理,

\4. 如果 To Space 無法足夠存盤某個物件,則將這個物件存盤到老生代,

\5. 在進行 GC 后,使用的便是 Eden Space 和 To Space 了,如此反復回圈,

\6. 當物件在 Survivor 區躲過一次 GC 后,其年齡就會+1,默認情況下年齡到達 15 的物件會被

移到老生代中

2.5.JAVA 四種參考型別

2.5.1. 強參考

在 Java 中最常見的就是強參考,把一個物件賦給一個參考變數,這個參考變數就是一個強引

用,當一個物件被強參考變數參考時,它處于可達狀態,它是不可能被垃圾回識訓制回收的,即

使該物件以后永遠都不會被用到 JVM 也不會回收,因此強參考是造成 Java 記憶體泄漏的主要原因之

一,

2.5.2. 軟參考

軟參考需要用 SoftReference 類來實作,對于只有軟參考的物件來說,當系統記憶體足夠時它

不會被回收,當系統記憶體空間不足時它會被回收,軟參考通常用在對記憶體敏感的程式中,

2.5.3. 弱參考

弱參考需要用 WeakReference 類來實作,它比軟參考的生存期更短,對于只有弱參考的物件

來說,只要垃圾回識訓制一運行,不管 JVM 的記憶體空間是否足夠,總會回收該物件占用的記憶體,

2.5.4. 虛參考

虛參考需要 PhantomReference 類來實作,它不能單獨使用,必須和參考佇列聯合使用,虛

參考的主要作用是跟蹤物件被垃圾回收的狀態,

2.6.GC 分代收集演算法 VS 磁區收集演算法

2.6.1. 分代收集演算法

當前主流 VM 垃圾收集都采用”分代收集”(Generational Collection)演算法, 這種演算法會根據

物件存活周期的不同將記憶體劃分為幾塊, 如 JVM 中的 新生代、老年代、永久代,這樣就可以根據

各年代特點分別采用最適當的 GC 演算法

2.6.1.1. 在新生代-復制演算法

每次垃圾收集都能發現大批物件已死, 只有少量存活. 因此選用復制演算法, 只需要付出少量

存活物件的復制成本就可以完成收集.

2.6.1.2. 在老年代-標記整理演算法

因為物件存活率高、沒有額外空間對它進行分配擔保, 就必須采用“標記—清理”或“標

記—整理”演算法來進行回收, 不必進行記憶體復制, 且直接騰出空閑記憶體.

2.6.2. 磁區收集演算法

磁區演算法則將整個堆空間劃分為連續的不同小區間, 每個小區間獨立使用, 獨立回收. 這樣做的

好處是可以控制一次回收多少個小區間 , 根據目標停頓時間, 每次合理地回收若干個小區間(而不是

整個堆), 從而減少一次 GC 所產生的停頓,

2.7.GC 垃圾收集器

Java 堆記憶體被劃分為新生代和年老代兩部分,新生代主要使用復制和標記-清除垃圾回收演算法;

年老代主要使用標記-整理垃圾回收演算法,因此 java 虛擬中針對新生代和年老代分別提供了多種不

同的垃圾收集器,JDK1.6 中 Sun HotSpot 虛擬機的垃圾收集器如下:

2.7.1. Serial 垃圾收集器(單執行緒、復制演算法)

Serial(英文連續)是最基本垃圾收集器,使用復制演算法,曾經是JDK1.3.1 之前新生代唯一的垃圾

收集器,Serial 是一個單執行緒的收集器,它不但只會使用一個 CPU 或一條執行緒去完成垃圾收集工

作,并且在進行垃圾收集的同時,必須暫停其他所有的作業執行緒,直到垃圾收集結束,

Serial 垃圾收集器雖然在收集垃圾程序中需要暫停所有其他的作業執行緒,但是它簡單高效,對于限

定單個 CPU 環境來說,沒有執行緒互動的開銷,可以獲得最高的單執行緒垃圾收集效率,因此 Serial

垃圾收集器依然是 java 虛擬機運行在 Client 模式下默認的新生代垃圾收集器,

2.7.2. ParNew 垃圾收集器(**Serial+多執行緒)**

ParNew 垃圾收集器其實是 Serial 收集器的多執行緒版本,也使用復制演算法,除了使用多執行緒進行垃

圾收集之外,其余的行為和 Serial 收集器完全一樣,ParNew 垃圾收集器在垃圾收集程序中同樣也

要暫停所有其他的作業執行緒,

ParNew 收集器默認開啟和 CPU 數目相同的執行緒數,可以通過-XX:ParallelGCThreads 引數來限

制垃圾收集器的執行緒數,【Parallel:平行的】

ParNew雖然是除了多執行緒外和Serial 收集器幾乎完全一樣,但是ParNew垃圾收集器是很多 java

虛擬機運行在 Server 模式下新生代的默認垃圾收集器,

2.7.3. Parallel Scavenge 收集器(多執行緒復制演算法、高效)

Parallel Scavenge 收集器也是一個新生代垃圾收集器,同樣使用復制演算法,也是一個多執行緒的垃

圾收集器,它重點關注的是程式達到一個可控制的吞吐量(Thoughput,CPU 用于運行用戶代碼

的時間/CPU 總消耗時間,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)),

高吞吐量可以最高效率地利用 CPU 時間,盡快地完成程式的運算任務,主要適用于在后臺運算而

不需要太多互動的任務,自適應調節策略也是 ParallelScavenge 收集器與 ParNew 收集器的一個

重要區別,

2.7.4. Serial Old 收集器(單執行緒標記整理演算法 )

Serial Old 是 Serial 垃圾收集器年老代版本,它同樣是個單執行緒的收集器,使用標記-整理演算法,

這個收集器也主要是運行在 Client 默認的 java 虛擬機默認的年老代垃圾收集器,

在 Server 模式下,主要有兩個用途:

\1. 在 JDK1.5 之前版本中與新生代的 Parallel Scavenge 收集器搭配使用,

\2. 作為年老代中使用 CMS 收集器的后備垃圾收集方案,

新生代 Serial 與年老代 Serial Old 搭配垃圾收集程序圖:

新生代 Parallel Scavenge 收集器與 ParNew 收集器作業原理類似,都是多執行緒的收集器,都使

用的是復制演算法,在垃圾收集程序中都需要暫停所有的作業執行緒,新生代 Parallel

Scavenge/ParNew 與年老代 Serial Old 搭配垃圾收集程序圖:

2.7.5. Parallel Old 收集器(多執行緒標記整理演算法)

Parallel Old 收集器是Parallel Scavenge的年老代版本,使用多執行緒的標記-整理演算法,在 JDK1.6

才開始提供,

在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老代的 Serial Old 收集器,只

能保證新生代的吞吐量優先,無法保證整體的吞吐量,Parallel Old 正是為了在年老代同樣提供吞

吐量優先的垃圾收集器,如果系統對吞吐量要求比較高,可以優先考慮新生代 Parallel Scavenge

和年老代 Parallel Old 收集器的搭配策略,

新生代 Parallel Scavenge 和年老代 Parallel Old 收集器搭配運行程序圖:

2.7.6. CMS 收集器(多執行緒標記清除演算法)

Concurrent mark sweep(CMS)收集器是一種年老代垃圾收集器,其最主要目標是獲取最短垃圾

回收停頓時間,和其他年老代使用標記-整理演算法不同,它使用多執行緒的標記-清除演算法,

最短的垃圾收集停頓時間可以為互動比較高的程式提高用戶體驗,

CMS 作業機制相比其他的垃圾收集器來說更復雜,整個程序分為以下 4 個階段:

2.7.6.1. 初始標記

只是標記一下 GC Roots 能直接關聯的物件,速度很快,仍然需要暫停所有的作業執行緒,

2.7.6.2. 并發標記

進行 GC Roots 跟蹤的程序,和用戶執行緒一起作業,不需要暫停作業執行緒,

2.7.6.3. 重新標記

為了修正在并發標記期間,因用戶程式繼續運行而導致標記產生變動的那一部分物件的標記

記錄,仍然需要暫停所有的作業執行緒,

2.7.6.4. 并發清除

清除 GC Roots 不可達物件,和用戶執行緒一起作業,不需要暫停作業執行緒,由于耗時最長的并

發標記和并發清除程序中,垃圾收集執行緒可以和用戶現在一起并發作業,所以總體上來看

CMS 收集器的記憶體回收和用戶執行緒是一起并發地執行,

CMS 收集器作業程序:

2.7.7. G1 收集器

Garbage first 垃圾收集器是目前垃圾收集器理論發展的最前沿成果,相比與 CMS 收集器,G1 收

集器兩個最突出的改進是:

\1. 基于標記-整理演算法,不產生記憶體碎片,

\2. 可以非常精確控制停頓時間,在不犧牲吞吐量前提下,實作低停頓垃圾回收,

G1 收集器避免全區域垃圾收集,它把堆記憶體劃分為大小固定的幾個獨立區域,并且跟蹤這些區域

的垃圾收集進度,同時在后臺維護一個優先級串列,每次根據所允許的收集時間,優先回收垃圾

最多的區域,區域劃分和優先級區域回識訓制,確保 G1 收集器可以在有限時間獲得最高的垃圾收

集效率,

2.8. JAVA IO/NIO

2.8.1. 阻塞 IO 模型

最傳統的一種 IO 模型,即在讀寫資料程序中會發生阻塞現象,當用戶執行緒發出 IO 請求之后,內

核會去查看資料是否就緒,如果沒有就緒就會等待資料就緒,而用戶執行緒就會處于阻塞狀態,用

戶執行緒交出 CPU,當資料就緒之后,內核會將資料拷貝到用戶執行緒,并回傳結果給用戶執行緒,用

戶執行緒才解除 block 狀態,典型的阻塞 IO 模型的例子為:data = socket.read();如果資料沒有就

緒,就會一直阻塞在 read 方法,

2.8.2. 非阻塞 IO 模型

當用戶執行緒發起一個 read 操作后,并不需要等待,而是馬上就得到了一個結果,如果結果是一個

error 時,它就知道資料還沒有準備好,于是它可以再次發送 read 操作,一旦內核中的資料準備

好了,并且又再次收到了用戶執行緒的請求,那么它馬上就將資料拷貝到了用戶執行緒,然后回傳,

所以事實上,在非阻塞 IO 模型中,用戶執行緒需要不斷地詢問內核資料是否就緒,也就說非阻塞 IO

不會交出 CPU,而會一直占用 CPU,典型的非阻塞 IO 模型一般如下:

    while(true){
        data = socket.read();
        if(data!= error){
            // 處理資料
            break;
        }
    }

但是對于非阻塞 IO 就有一個非常嚴重的問題,在 while 回圈中需要不斷地去詢問內核資料是否就

緒,這樣會導致 CPU 占用率非常高,因此一般情況下很少使用 while 回圈這種方式來讀取資料,

2.8.3. 多路復用 IO 模型

多路復用 IO 模型是目前使用得比較多的模型,Java NIO 實際上就是多路復用 IO,在多路復用 IO

模型中,會有一個執行緒不斷去輪詢多個 socket 的狀態,只有當 socket 真正有讀寫事件時,才真

正呼叫實際的 IO 讀寫操作,因為在多路復用 IO 模型中,只需要使用一個執行緒就可以管理多個

socket,系統不需要建立新的行程或者執行緒,也不必維護這些執行緒和行程,并且只有在真正有

socket 讀寫事件進行時,才會使用 IO 資源,所以它大大減少了資源占用,在 Java NIO 中,是通

過 selector.select()去查詢每個通道是否有到達事件,如果沒有事件,則一直阻塞在那里,因此這

種方式會導致用戶執行緒的阻塞,多路復用 IO 模式,通過一個執行緒就可以管理多個 socket,只有當

socket 真正有讀寫事件發生才會占用資源來進行實際的讀寫操作,因此,多路復用 IO 比較適合連

接數比較多的情況,

另外多路復用 IO 為何比非阻塞 IO 模型的效率高是因為在非阻塞 IO 中,不斷地詢問 socket 狀態

是通過用戶執行緒去進行的,而在多路復用 IO 中,輪詢每個 socket 狀態是內核在進行的,這個效

率要比用戶執行緒要高的多,

不過要注意的是,多路復用 IO 模型是通過輪詢的方式來檢測是否有事件到達,并且對到達的事件

逐一進行回應,因此對于多路復用 IO 模型來說,一旦事件回應體很大,那么就會導致后續的事件

遲遲得不到處理,并且會影響新的事件輪詢,

2.8.4. 信號驅動 IO 模型

在信號驅動 IO 模型中,當用戶執行緒發起一個 IO 請求操作,會給對應的 socket 注冊一個信號函

數,然后用戶執行緒會繼續執行,當內核資料就緒時會發送一個信號給用戶執行緒,用戶執行緒接收到

信號之后,便在信號函式中呼叫 IO 讀寫操作來進行實際的 IO 請求操作,

2.8.5. 異步 IO 模型

異步 IO 模型才是最理想的 IO 模型,在異步 IO 模型中,當用戶執行緒發起 read 操作之后,立刻就

可以開始去做其它的事,而另一方面,從內核的角度,當它受到一個 asynchronous read 之后,

它會立刻回傳,說明 read 請求已經成功發起了,因此不會對用戶執行緒產生任何 block,然后,內

核會等待資料準備完成,然后將資料拷貝到用戶執行緒,當這一切都完成之后,內核會給用戶執行緒

發送一個信號,告訴它 read 操作完成了,也就說用戶執行緒完全不需要實際的整個 IO 操作是如何

進行的,只需要先發起一個請求,當接收內核回傳的成功信號時表示 IO 操作已經完成,可以直接

去使用資料了,

也就說在異步 IO 模型中,IO 操作的兩個階段都不會阻塞用戶執行緒,這兩個階段都是由內核自動完

成,然后發送一個信號告知用戶執行緒操作已完成,用戶執行緒中不需要再次呼叫 IO 函式進行具體的

讀寫,這點是和信號驅動模型有所不同的,在信號驅動模型中,當用戶執行緒接收到信號表示資料

已經就緒,然后需要用戶執行緒呼叫 IO 函式進行實際的讀寫操作;而在異步 IO 模型中,收到信號

表示 IO 操作已經完成,不需要再在用戶執行緒中呼叫 IO 函式進行實際的讀寫操作,

注意,異步 IO 是需要作業系統的底層支持,在 Java 7 中,提供了 Asynchronous IO,

更多參考: http://www.importnew.com/19816.html

2.8.1. JAVA IO

2.8.2. JAVA NIO

NIO 主要有三大核心部分:Channel(通道),Buffer(緩沖區), Selector,傳統 IO 基于位元組流和字

符流進行操作,而 NIO 基于 Channel 和 Buffer(緩沖區)進行操作,資料總是從通道讀取到緩沖區

中,或者從緩沖區寫入到通道中,Selector(選擇區)用于監聽多個通道的事件(比如:連接打開,

資料到達),因此,單個執行緒可以監聽多個資料通道,

NIO 和傳統 IO 之間第一個最大的區別是,IO 是面向流的,NIO 是面向緩沖區的,

2.8.2.1.

NIO 的緩沖區

Java IO 面向流意味著每次從流中讀一個或多個位元組,直至讀取所有位元組,它們沒有被快取在任何

地方,此外,它不能前后移動流中的資料,如果需要前后移動從流中讀取的資料,需要先將它緩

存到一個緩沖區,NIO 的緩沖導向方法不同,資料讀取到一個它稍后處理的緩沖區,需要時可在

緩沖區中前后移動,這就增加了處理程序中的靈活性,但是,還需要檢查是否該緩沖區中包含所

有您需要處理的資料,而且,需確保當更多的資料讀入緩沖區時,不要覆寫緩沖區里尚未處理的

資料,

2.8.2.2.

NIO 的非阻塞

IO 的各種流是阻塞的,這意味著,當一個執行緒呼叫 read() 或 write()時,該執行緒被阻塞,直到有

一些資料被讀取,或資料完全寫入,該執行緒在此期間不能再干任何事情了, NIO 的非阻塞模式,

使一個執行緒從某通道發送請求讀取資料,但是它僅能得到目前可用的資料,如果目前沒有資料可

用時,就什么都不會獲取,而不是保持執行緒阻塞,所以直至資料變的可以讀取之前,該執行緒可以

繼續做其他的事情, 非阻塞寫也是如此,一個執行緒請求寫入一些資料到某通道,但不需要等待它

完全寫入,這個執行緒同時可以去做別的事情, 執行緒通常將非阻塞 IO 的空閑時間用于在其它通道上

執行 IO 操作,所以一個單獨的執行緒現在可以管理多個輸入和輸出通道(channel),

2.8.3. Channel

首先說一下 Channel,國內大多翻譯成“通道”,Channel 和 IO 中的 Stream(流)是差不多一個

等級的,只不過 Stream 是單向的,譬如:InputStream, OutputStream,而 Channel 是雙向

的,既可以用來進行讀操作,又可以用來進行寫操作,

NIO 中的 Channel 的主要實作有:

\1. FileChannel

\2. DatagramChannel

\3. SocketChannel

\4. ServerSocketChannel

這里看名字就可以猜出個所以然來:分別可以對應檔案 IO、UDP 和 TCP(Server 和 Client),

下面演示的案例基本上就是圍繞這 4 個型別的 Channel 進行陳述的,

2.8.4. Buffer

Buffer,故名思意,緩沖區,實際上是一個容器,是一個連續陣列,Channel 提供從檔案、

網路讀取資料的渠道,但是讀取或寫入的資料都必須經由 Buffer,

上面的圖描述了從一個客戶端向服務端發送資料,然后服務端接收資料的程序,客戶端發送

資料時,必須先將資料存入 Buffer 中,然后將 Buffer 中的內容寫入通道,服務端這邊接收資料必

須通過 Channel 將資料讀入到 Buffer 中,然后再從 Buffer 中取出資料來處理,

在 NIO 中,Buffer 是一個頂層父類,它是一個抽象類,常用的 Buffer 的子類有:

ByteBuffer、IntBuffer、 CharBuffer、 LongBuffer、 DoubleBuffer、FloatBuffer、

ShortBuffer

2.8.5. Selector

Selector 類是 NIO 的核心類,Selector 能夠檢測多個注冊的通道上是否有事件發生,如果有事

件發生,便獲取事件然后針對每個事件進行相應的回應處理,這樣一來,只是用一個單執行緒就可

以管理多個通道,也就是管理多個連接,這樣使得只有在連接真正有讀寫事件發生時,才會呼叫

函式來進行讀寫,就大大地減少了系統開銷,并且不必為每個連接都創建一個執行緒,不用去維護

多個執行緒,并且避免了多執行緒之間的背景關系切換導致的開銷,

2.9.JVM 類加載機制

JVM 類加載機制分為五個部分:加載,驗證,準備,決議,初始化,下面我們就分別來看一下這

五個程序,

2.9.1.1.

加載

加載是類加載程序中的一個階段,這個階段會在記憶體中生成一個代表這個類的 java.lang.Class 對

象,作為方法區這個類的各種資料的入口,注意這里不一定非得要從一個 Class 檔案獲取,這里既

可以從 ZIP 包中讀取(比如從 jar 包和 war 包中讀取),也可以在運行時計算生成(動態代理),

也可以由其它檔案生成(比如將 JSP 檔案轉換成對應的 Class 類),

2.9.1.2.

驗證

這一階段的主要目的是為了確保 Class 檔案的位元組流中包含的資訊是否符合當前虛擬機的要求,并

且不會危害虛擬機自身的安全,

2.9.1.3.

準備

準備階段是正式為類變數分配記憶體并設定類變數的初始值階段,即在方法區中分配這些變數所使

用的記憶體空間,注意這里所說的初始值概念,比如一個類變數定義為:

public static int v = 8080;

實際上變數 v 在準備階段過后的初始值為 0 而不是 8080,將 v 賦值為 8080 的 put static 指令是

程式被編譯后,存放于類構造器<client>方法之中,

但是注意如果宣告為:

public static final int v = 8080;

在編譯階段會為 v 生成 ConstantValue 屬性,在準備階段虛擬機會根據 ConstantValue 屬性將 v

賦值為 8080,

2.9.1.4.

決議

決議階段是指虛擬機將常量池中的符號參考替換為直接參考的程序,符號參考就是 class 檔案中

的:

\1. CONSTANT_Class_info

\2. CONSTANT_Field_info

\3. CONSTANT_Method_info

等型別的常量,

2.9.1.5. 符號參考

? 符號參考與虛擬機實作的布局無關,參考的目標并不一定要已經加載到記憶體中,各種虛擬

機實作的記憶體布局可以各不相同,但是它們能接受的符號參考必須是一致的,因為符號引

用的字面量形式明確定義在 Java 虛擬機規范的 Class 檔案格式中,

2.9.1.6. 直接參考

? 直接參考可以是指向目標的指標,相對偏移量或是一個能間接定位到目標的句柄,如果有

了直接參考,那參考的目標必定已經在記憶體中存在,

2.9.1.7.

初始化

初始化階段是類加載最后一個階段,前面的類加載階段之后,除了在加載階段可以自定義類加載

器以外,其它操作都由 JVM 主導,到了初始階段,才開始真正執行類中定義的 Java 程式代碼,

2.9.1.8. 類構造器<client>

初始化階段是執行類構造器<client>方法的程序,<client>方法是由編譯器自動收集類中的類變

量的賦值操作和靜態陳述句塊中的陳述句合并而成的,虛擬機會保證子<client>方法執行之前,父類

的<client>方法已經執行完畢,如果一個類中沒有對靜態變數賦值也沒有靜態陳述句塊,那么編譯

器可以不為這個類生成<client>()方法,

注意以下幾種情況不會執行類初始化:

\1. 通過子類參考父類的靜態欄位,只會觸發父類的初始化,而不會觸發子類的初始化,

\2. 定義物件陣列,不會觸發該類的初始化,

\3. 常量在編譯期間會存入呼叫類的常量池中,本質上并沒有直接參考定義常量的類,不會觸

發定義常量所在的類,

\4. 通過類名獲取 Class 物件,不會觸發類的初始化,

\5. 通過 Class.forName 加載指定類時,如果指定引數 initialize 為 false 時,也不會觸發類初

始化,其實這個引數是告訴虛擬機,是否要對類進行初始化,

\6. 通過 ClassLoader 默認的 loadClass 方法,也不會觸發初始化動作,

2.9.2. 類加載器

虛擬機設計團隊把加載動作放到 JVM 外部實作,以便讓應用程式決定如何獲取所需的類,JVM 提

供了 3 種類加載器:

2.9.2.1. 啟動類加載器(Bootstrap ClassLoader)

\1. 負責加載 JAVA_HOME\lib 目錄中的,或通過-Xbootclasspath 引數指定路徑中的,且被

虛擬機認可(按檔案名識別,如 rt.jar)的類,

2.9.2.2. 擴展類加載器(Extension ClassLoader)

\2. 負責加載 JAVA_HOME\lib\ext 目錄中的,或通過 java.ext.dirs 系統變數指定路徑中的類

庫,

2.9.2.3. 應用程式類加載器(Application ClassLoader):

\3. 負責加載用戶路徑(classpath)上的類別庫,

JVM 通過雙親委派模型進行類的加載,當然我們也可以通過繼承 java.lang.ClassLoader

實作自定義的類加載器,

2.9.3. 雙親委派

當一個類收到了類加載請求,他首先不會嘗試自己去加載這個類,而是把這個請求委派給父

類去完成,每一個層次類加載器都是如此,因此所有的加載請求都應該傳送到啟動類加載其中,

只有當父類加載器反饋自己無法完成這個請求的時候(在它的加載路徑下沒有找到所需加載的

Class),子類加載器才會嘗試自己去加載,

采用雙親委派的一個好處是比如加載位于 rt.jar 包中的類 java.lang.Object,不管是哪個加載

器加載這個類,最終都是委托給頂層的啟動類加載器進行加載,這樣就保證了使用不同的類加載

器最終得到的都是同樣一個 Object 物件,

2.9.4. OSGI**(動態模型系統)**

OSGi(Open Service Gateway Initiative),是面向 Java 的動態模型系統,是 Java 動態化模塊化系

統的一系列規范,

2.9.4.1. 動態改變構造

OSGi 服務平臺提供在多種網路設備上無需重啟的動態改變構造的功能,為了最小化耦合度和促使

這些耦合度可管理,OSGi 技術提供一種面向服務的架構,它能使這些組件動態地發現對方,

2.9.4.2. 模塊化編程與熱插拔

OSGi 旨在為實作 Java 程式的模塊化編程提供基礎條件,基于 OSGi 的程式很可能可以實作模塊級

的熱插拔功能,當程式升級更新時,可以只停用、重新安裝然后啟動程式的其中一部分,這對企

業級程式開發來說是非常具有傭訓力的特性,

OSGi 描繪了一個很美好的模塊化開發目標,而且定義了實作這個目標的所需要服務與架構,同時

也有成熟的框架進行實作支持,但并非所有的應用都適合采用 OSGi 作為基礎架構,它在提供強大

功能同時,也引入了額外的復雜度,因為它不遵守了類加載的雙親委托模型,

每天努力一點,每天都在進步

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/350776.html

標籤:其他

上一篇:【面試】北京Python后端開發

下一篇:Linux、Windows安裝ActiveMQ

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more