--- title: 'JVM 歷史、編譯 JDK' disqus: kyleAlien --- JVM 歷史、編譯 JDK === ## Overview of Content 如有引用參考請詳註出處,感謝 :cat: Java 不僅僅是開發語言,它也是一系列計算機應用、規範組成的 **體系**,該技術體系提供了完整的軟體開發、跨平台佈署...等等的環境(像是包括嵌入式、移動裝置、服務器) [TOC] ## Java 技術體系 運行在 JVM 上的語言除了 Java 之外,還有 Kotlin, Clojure, JRuby, Groovy... 等等,這些都算是 Java 技術體系中的一員;一般來講 Java 技術體系包括 * Java 程序設計語言 * Java Library API * 各平台的 JVM 實現 * Class 文件格式 * 其他開源第三方 Library ### 照組成劃分 * 根據 Java 各個組成部分的功能,**JDK(`Java Development Kit`)是 Java 程序開發的最小環境** * Java 程序設計語言 * Java Library API * 各平台的 JVM 實現 :::info * **JRE (`Java Runtime Environment`)是指**? 是指 Java Library API 中的 **`Java SE`、`JVM` 這兩部份的組成**,只要有這兩個元素就可以運行 Java 程序 > ![](https://hackmd.io/_uploads/ByirYk0hn.png) ::: ### 照服務領域劃分 - JCP/JSR * 根據 Java 的技術服務領域,又可分為 4 個主要產品;而這些 API 都是業界共同制定的標準,業界代表可參與 **JCP** (`Java Community Process`)、審核、投票,決定平台元件、特性、應用程式介面... 等等 > 而訂製出來的標準會以 **JSR**(`Java Specification Requests`)作為正式標準規範文件,不同的技術解決方案都會給予一個編號 > > 在 JSR 規範的表準之下,各廠商都可以實現自己的成品!(相當於每個廠商都有不同的實作) * **Java Card** 支持 Java 小程序(`Applets`),它運行在 **小內存設備上的平台** > 智能卡、支付卡、門禁卡...等等 * **Java ME**(`Micro Edition`) 支持 Java 程序運行在 **移動端上的平台**,它的特點是它對 Java API 進行精簡,並加入移動端的特性 > 運行在小型嵌入設備上 :::info * JDK 6 之前稱為 J2ME ::: :::warning * 然而 Android 平台上並不使用 Java ME,**Android 平台使用 JSE** ::: * **Java SE**(`Standard Edition`) 支持 **桌面等級應用**,它提供完整的 Java 核心 API :::info * JDK 6 之前稱為 J2SE ::: * **Java EE**(`Enterprise Edition`) 支持 **多層級架構的企業應用**,其特色是除了標準 API 之外,還有大量的擴充 API > ERP, MIS, CRM... 等等應用 :::success * JDK 6 之前稱為 J2EE * JavaEE 6 使用的規範是 [**JSR 316**](https://jcp.org/en/jsr/detail?id=316);而 Servelet 3.0 規範則是 [**JSR 315**](https://jcp.org/en/jsr/detail?id=315),Servelet 在 Java EE 中,主要是在接收客戶端的請求 ::: ## Java 歷史簡介 這裡做個 Java 歷史的簡介 ### Sun 時代 * 最一開始 Java 是 **`Sun` 公司的產品**,它的重點事蹟如下 * 原始名稱為 Oak,後來才改名為 Java * 開發理念為 **Write Once, Run Anywhere** * Sun 時代 版本差異 | JDK 版本 | 說明 | 技術重點補充 | | - | - | - | | 1.1 | **有 Java 中最基礎的技術支持**:Jar 文件格式、JDBC、JavaBeans、RMI... 等等 | InnerClass, Reflection 的出現 | | 1.2 | JDK 重要里程碑,**依照服務將其分為 J2SE, J2EE, J2ME... 等等** | EJB, Java Plugin, Java IDL, Swing, Collection.. (**JVM 中新增 JIT 技術,並出現 `Classic VM`, `HotSpot VM`, `Exact VM`**)| | 1.3 | **HotSpot VM 的出現**,並預設為 Java 默認虛擬機 | Java 2D API, Java Sound API | | 1.4 | 開始穩定成熟 | 正則表達式、異常鏈、NIO、異常類、XML 解析... 等等 | | 5 | 全面 **改由 Java x 發布** | 自動裝箱、泛型、動態註解、枚舉...等等;改進虛擬機中的內存模型(JMM);併發包 | | 6 | **初步的動態語言支持** | JVM 改進了鎖、同步、GC、類加載...等等 | | | **Java 開源**,並建立 OpenJDK 組織對源碼進行管理 | - | | 7 | 由於經濟問題,導致發布延期(最終被 Sun 收購) | Lambda(**函數式編成**), Jigsaw(虛擬機層面的模塊化), COIN... | :::info * **到 JDK7 為止,Oracle 公司收購了 Sun 公司** ::: ### Oracle 時代 * Oracle 公司收購後極具商業化風格 * 宣佈 JDK7 維護到 2022 年,在這期間 JDK7 的所有功能都可以在 Mac OS X、Window 上運行 * Oracle 接手後的版本差異 | JDK 版本 | 說明 | 技術重點補充 | | - | - | - | | 7 | G1 收集器 | 延後 Lambda, Coin ... 等等項目 | | 8 | 完成 Lambda, 新的 時間、日期 API, Nashorn JavaScript 引擎支持 | 移除 JVM 中的永久代 | | 9 | Oracle 堅持 **發展 VM 模塊化技術 Jigsaw** | 增強 JS Shell, JLink, JHSDB... 等等,並統整了 HotSpot 各個模塊的日誌系統,支持 Http2 客戶端 API | | | 使用敏捷開發 | 在此之後的版本都以 Java x.y 為準 (y 為月份),Java 1.x 變成別名 | | | JDK 更新週期改為 6 個月一次,並且只有 LTS 版本才會長期支援 | - | | 10 | 主要是 **內部重構** | 統一源倉庫、GC 界面、JIT 界面 | | | Google 被告使用 Java API 侵權(並不關虛擬機,針對使用 Java 語言) | 出現 **==Graal 編譯器==** | | 11(LTS) | **ZGC 革命性出現** | 把 JDK 11 之前的特性開放給 OpenJDK 組織 | | | 發布分為兩個版本 JDK:商業收費版本(`OracleJDK`)、免費版(`OpenJDK`) | 免費板只支持半年的更新 | | 12 | Switch 表達式、Java 微測套件(`JMH`)... 等等功能 | - | :::success * **Oracle JDK 開始收費了嗎**? 其實不然,這是給使用者自行選擇,在 JDK 11 之後,可以選擇付費(長期支援),或是免費(你要一直更新) ::: ### JDK 開分支策略 * 由於 Sun 公司被 Oracle 公司接管 Java 時是在 Java 6 時期(Java 7 未發布),因此他們改變了管理專案的分支策略 1. 剝離原本要發布 JDK 7 的功能,對外公佈穩定 JDK6 分支(並且 6 可不斷更新) ``` mermaid graph TD; JDK6_Main-->JDK7_Dev; JDK6_Main-->JDK6u1; JDK6u1-->JDK6u4; JDK6u4-->JDK6u10; JDK6u10-->JDK6u26; ``` 2. JDK7 經過測試、功能穩定後,發布 JDK7,並同時在 JDK7 發布版上建立 JD8 為下一代做準備 ``` mermaid graph TD; JDK6-->JDK7_Main; JDK7_Main-->JDK8_Dev; JDK7_Main-->JDK7u1; JDK7u1-->JDK7u4; JDK7u4-->JDK7u10; JDK7u10-->JDK7u26; ``` ## 編譯 JDK Java 類中有許多底層方法(Native),了解這些方法的細節實做,可以對於調適 VM 有不小的幫助 ### 下載 Java 源碼 * **在 Sun 的後期(`JDK6` 時建立 OpenJDK 組織)將 Java 開源**,而之後使用 OpenJDK 源碼衍生出的多個發行板(`Azul Zulu`、`Oracle JDK`、`Oracle Open JDK`、`AdoptOpenJDK`、`AmazonCorretto`... 等等) **OpenJDK 中的源碼倉庫,只包含了標準 Java SE 的代碼**,如果須需要額外模塊則須另外下載 :::warning * 也就是說每個發行板的 OpenJDK 有的功能不盡相同,只能保證一定有 `Java SE` 的實現代碼 ::: :::info * **在 Java 11 中,OracleJDK 與 OpenJDK 的實現已經非常接近相同** ::: * 藉此我們可以使用 [**OpenJDK**](https://openjdk.org/) 的版本進行研究,下載源碼方式如下 > **以下載 JDK 12 為例** 1. **透過 Mercurial 代碼管理工具** 下載 JDK 源碼 ```shell= sudo apt install mercurial hg clone http://hg.openjdk.java.net/jdk/jdk cd jdk # 查看指定 tag 並切換指定版本 hg log | grep tag # 切換到 JDK12+1 hg update -r jdk-12+1 # 確認 hg summart ``` > ![](https://hackmd.io/_uploads/HJKMRH1pn.png) 2. **透過 [**github**](https://github.com/openjdk/jdk) 下載 JDK 源碼** ```shell= git clone https://github.com/openjdk/jdk.git git tag | grep jdk-12 # 切換到 JDK12+33 git checkout jdk-12+33 # 確認 git branch ``` > ![](https://hackmd.io/_uploads/ByKhOEuT2.png) :::info * 個人習慣使用 Git、Github,所以採用這個方案 ::: 3. 手動下載 [**JDK 壓縮包**](https://hg.openjdk.org/jdk/jdk12):點擊左邊 Browse 再點擊壓縮包(`zip`, `gz`... 等等) > ![](https://hackmd.io/_uploads/HyJDJ8kT2.png) ### 編譯 JDK - 環境需求 * **環境需求**: * **OS 平台**:建議在 Linux or MacOS 上進行編譯,可以少走一些坑 > 目前我使用 Ubuntu 20 * **磁碟空間**:建議準備個 10 G 以上的空間,因為在 **編譯期間會產生不少中間文件** (IR File) * **路徑**:建議是使用純英文的空間路徑 ### 編譯 JDK - 工具需求 Bootstrap JDK * 編譯 JDK 除了建議環境之外,還需要一些 **系統工具** * **NativeCode 編譯工具**:也就是 C、C++ 編譯工具,這邊可以使用 `GCC` or `CLang` 編譯工具 :::warning * `GCC` 版本最低為 4.8 * `CLang` 版本最低為 3.2 ::: ```shell= sudo apt install -y build-essential gcc --version ``` > ![](https://hackmd.io/_uploads/B1vSHIkpn.png) * **第三方工具**:OpenJDK 還依賴一些第三方編譯工具,可依照需求做安裝 | 工具名 | 庫名 | 安裝包 | | - | - | - | | FreeType | The FreeType Project | `libfreetype6-dev` | | CUPS | Common UNIX Printing System | `libcups2-dev` | | X11 | X Window System | `libx11-dev`、`libxext-dev`、`libxrender-dev`、`libxtst-dev`、`libxt-dev`| | ALSA | Advanced Linux Sound Architecture | `libasound2-dev` | | libffi | Portable Foreign Function Interface Library | `libffi-dev` | | autoconf | Exetensible PAckage of M4 Macros | `autoconf` | ```shell= sudo apt install -y libfreetype6-dev \ libcups2-dev \ libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev \ libasound2-dev \ libffi-dev \ autoconf \ build-essential \ zip unzip \ git \ libfontconfig1-dev ``` * **Bootstrap JDK**: 編譯版號為為 N 的 JDK 時,需要有 JDK(N - 1) 版的工具,這種 N-1 版本的 JDK 稱為 Bootstrap JDK; > 假設現在要編譯 OpenJDK 12,那我們就要先安裝 OpenJDK 11 ```shell= sudo apt install -y openjdk-11-jdk ``` ### 編譯 JDK & 參數設置 * JDK 編譯會透過一個 `autoconf` 工具來協助,讓使用者免去關注各個硬體平台差異的 Options 設定(所以請記得安裝該工具) 在編譯 JDK 前我們可以先查看 configure 可以做哪些設定,透過**設定 configure 也會影響到最終 Make 指令編譯出來的結果** ```shell= # 查看完整可設定的 Options bash configure --help ``` > ![](https://hackmd.io/_uploads/BJqvsUkah.png) 下表為常用的幾個設定值 | Options | 功能說明 | 補充 | | - | - | - | | `--with-debug-level=<level>` | 設定調適等級 | `release`(默認)、`fastdebug`、`slowdebug`... | | `--enable-debug` | 等於 `fastdebug` 調適等級 | - | | `--with-native-debug-symbols=<method>` | 指定要調適的符號信息 | `non`、`internal`、`external`、`zipped` | | `--with-version-string=<String>` | 設置編譯 JDK 的版號 | 這會影響最終編譯出 JDK 的版本訊息(`java --version`) | | `with-jvm-variants=<variants>` | 編譯特定模式的 HotSpot JVM | `server`、`client`、`core`、`monimal`、`zero`、`custom` | | `--with-target-bits=<bits>` | 指名要編譯出 32, 64 位元的 JVM | 64 位元的機台上可以交叉編譯出 32 bit 的 JVM | | `--with-<lib>=<path>` | 用於指明依賴包的具體路徑 | - | | `--with-extra-<flagtype>=<flags>` | 該設定會作用在 C, C++, Java 代碼編譯時期 | 像是 `cflags`, `cxxflags`, `ldflags`... | | `--with-conf-name=<name>` | 指定編譯配置名稱 | - | * **編譯 JDK 12** 1. **設定參數**: ```shell= bash configure --enable-debug --with-jvm-variants=server ``` :::warning * **configure 設定失敗?** 當 configure 設定失敗時,它的返回碼就會是非 0(0 才是成功),這時你就需要按照提示去安裝、設置某些必要工具或參數 > ![](https://hackmd.io/_uploads/H1mM1P1p3.png) ::: 設置成功後會看到 configure 摘要訊息 > ![](https://hackmd.io/_uploads/ByWYJwJ6n.png) 2. **執行 make 指令開始編譯** :::warning * 如果你執行多次 make 那會產生多個檔案,這時可以用 `make clean` 清理 ::: ```shell= make jdk ``` :::danger * **JDK 12 編譯失敗**? 出現 `BUILD_TOOLS_LANGTOOLS.vardeps` 這是因為 **JDK12 只支援 4.3 版本以下的 make**,所以我們要找到 `./make/common/MakeBase.gmk` 檔案,並找到 `DependOnVariableHelper` 關鍵字,手動修改程如下 ```shell= DependOnVariableHelper = \ $(strip \ $(eval $1_filename := $(call DependOnVariableFileName, $1, $2)) \ $(if $(wildcard $($1_filename)), $(eval include $($1_filename))) \ $(if $(call equals, $(strip $($1)), $(strip $($1_old))),,\ $(call MakeDir, $(dir $($1_filename))) \ $(if $(findstring $(LOG_LEVEL), trace), \ $(info NewVariable $1: >$(strip $($1))<) \ $(info OldVariable $1: >$(strip $($1_old))<)) \ $(call WriteFile, $1_old:=$(call DoubleDollar,$(call EscapeHash,$($1))), \ $($1_filename))) \ $($1_filename) \ ) ``` ::: ### 編譯 JDK 建議 - Docker * 編譯 JDK 最常碰到的是環境問題,每個版本的 JDK 都有偏好環境、處理工具的版本... 等等需求;而我們可以透過以下方法解決 1. 依照 JDK 編譯需求,去改變當前系統的工具、環境(不太推薦) * 修改 JDK 源碼去符合當前環境 * 下載所需的工具並自己編譯程式安裝到當前平台上 :::info * 但老實說以上方法確實可以,但卻相當麻煩又不好處理!工具之間的版本相互依賴、過時工具... 等等問題非常不好處理 ::: 2. **創建符合編譯 JDK 的環境**(推薦,可以使用 Docker) * 這個最直覺的就是創建虛擬 OS 平台,再透過該平台來編譯 JDK :::success * 這是個很好的辦法,我們 **可以在 Docker 上建立編譯 JDK 所需的環境** 像是 JDK 12 就可以在 `Ubuntu:18.04` 編譯 ::: * 接下來 **使用 Docker 創建一個環境來編譯 JDK 12** > 安裝請參考官方網站,基礎使用可參考另外一篇 [**Docker 安裝、映像檔使用**](https://hackmd.io/tARjfVCSQTy-aG4PtPo2eQ?view#Docker-%E5%AE%89%E8%A3%9D%E3%80%81%E6%98%A0%E5%83%8F%E6%AA%94%E4%BD%BF%E7%94%A8) 1. **下載 OS 檔案**: 使用 `pull` 下載 `Ubuntu 18.04` ```shell= # 搜尋對應的版本 sudo docker search ubuntu:18.04 # 下載 `Ubuntu 18.04` sudo docker pull ubuntu:18.04 # 查看所有 images sudo docker images ``` > ![](https://hackmd.io/_uploads/rkq7OKPah.png) 2. **建立、運行 OS,並指定本地檔的映射**: :::info * 下載請參考上面小節(目前已經下載好 JDK12) ::: ```shell= # 創建 docker 資料夾 mkdir ~/docker/ # 將原本下載好的 docker 移動到 ~/docker/ 資料夾下 mv ~/Documents/github/Learning/JDK/downloadJDK ~/docker/ # 運行 ubuntu 並將 `~/docker` 資料夾映射到 ubuntu:18.04 中的 `/opt` 資料夾 sudo docker run -it -v ~/docker:/opt/ ubuntu:18.04 /bin/bash ``` 3. **下載基礎工具** ```shell= sudo apt install -y libfreetype6-dev \ libcups2-dev \ libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev \ libasound2-dev \ libffi-dev \ autoconf \ build-essential \ zip unzip \ git \ libfontconfig1-dev sudo apt install -y openjdk-11-jdk ``` 4. **改變 Docker Container 中 Ubuntu OS 的設置**: 使其可以運行 JDK12 的編譯 ```shell= # 安裝 gcc 4.8 版本 update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100 # 安裝 g++ 4.8 版本 update-alternatives --install /usr/bin/gcc gcc /usr/bin/g++-4.8 100 ``` > ![](https://hackmd.io/_uploads/ByCtRFDTh.png) 5. **設置 JDK config** ```shell= bash configure --enable-debug --with-jvm-variants=server --disable-warnings-as-errors ``` > ![](https://hackmd.io/_uploads/SJxNBqPa3.png) 6. **編譯 JDK 12,並驗證編譯結果** ```shell= # 譯 JDK 12 make ``` > ![](https://hackmd.io/_uploads/SykUjV_an.png) :::warning * 如果還編譯失敗,可以考慮先執行 `make clean`,並再次執行 `make` ::: 驗證編譯結果確認是 JDK 12 ```shell= ./build/linux-x86_64-normal-server-fastdebug/jdk/bin/java --version ``` > ![](https://hackmd.io/_uploads/HkZuoE_an.png) 7. **編譯 JDK image**: ```shell= make images ls -laF ./build/linux-x86_64-normal-server-fastdebug/images/ ``` > ![](https://hackmd.io/_uploads/SyLcjwOp2.png) ## 其他 ### 編譯 JDK 目標 * make 除了上述之外(無指定),還可以指定不同目標產生不同作用 | make 目標 | 功能 | | - | - | | `docs-image` | 產生 JDK 的文檔 image | | `test-image` | 產生 JDK 的測試 image | | `bootcycle-image` | 編譯兩次 JDK,第二次使用第一次的編譯結果作為 Bootstrap JDK | | `all-image` | 產生所有 image(相當於 `product`, `docs`, `test`)三個編譯目標 | | `hotspot` | 只編譯 Hotspot 虛擬機 | | `clean` | 清理 make 指令產生的臨時文件! | | `dist-clean` | 清理 make、configure 指令產生的文件(相當於回歸到最初的檔案) | ### 編譯 JDK - 產生目錄 * 編譯完 JDK 後會產生以下常見目錄,它們功能如下 | make 結果 | 功能 | | - | - | | `buildtools/` | 用於生成、存放編譯過程中使用到的工具 | | `hotspot/` | HotSpot 虛擬機產生的中間文件 | | `images/` | 使用 `make *-image` 相關指令產生的 image 檔案 | | `jdk/` | 編譯後產生的 JDK 文件 | | `support/` | 存放編譯時期產生的中間文件 | | `test-results/` | 存放編譯後的自動化測試結果 | | `configure-support/`、`male-support/`、`test-support/` | 存放執行 `configure`、`make`、`test` 的臨時文件 | > ![](https://hackmd.io/_uploads/H1xCjN_ah.png) ### 重用 Docker 環境 * 在前面範例中,我們有使用 Docker 建立對應符合固有版本 JDK 的 OS 環境,為了將來方便重用,我們可以把這個特定的 OS 儲存 ```shell= sudo docker ps -a # 提交指定 OS (儲存) sudo docker commit -m "Ubuntu 18.04 for JDK" 49acf ubuntu:18.04_JDK # 查看建立好的 image 檔案 sudo docker images ``` > ![](https://hackmd.io/_uploads/Bk6wkB_62.png) ### CLion 調適 JDK * 以下示範使用 CLion 來調適 JDK(當然你也可以傳統一點使用 GDB 命令、VIM 調適) 1. **開啟指定 JDK 專案** > ![](https://hackmd.io/_uploads/HJxh0wuan.png) 2. 這裡先選擇 **自動產生 `CMakeList.txt`** > ![](https://hackmd.io/_uploads/r1sWydOah.png) 但預設的 `CMakeList.txt` 是不能使用的 > ![](https://hackmd.io/_uploads/By7tkd_a3.png) :::success * 正確的 `CMakeList.txt` 可以參考 [**ojdkbuild 設置**](https://github.com/ojdkbuild/ojdkbuild),下載專案並複製其中的 `CMakeList.txt` 檔案 ::: 3. 接著我們要自己 **建立一個 `CMake Application`** > ![](https://hackmd.io/_uploads/Bk2n1_OTh.png) 3. **設定啟動的 `Executable`、`target`、`Program argument`... 等等資訊** * 設定 `Executable` 為上面編譯好的 Java 程式 > ![](https://hackmd.io/_uploads/S1xPl__p2.png) * 設定 `Program argments` 如下 ```shell= --version -XX:+TraceBytecodes -XX:StopInterpreterAt=<n> ``` :::info * `-XX:+TraceBytecodes -XX:StopInterpreterAt=<n>` 該設置值是因為 Hotspot 在主流的操作系統上是採用 **模板解釋器執行字節碼的**(與即時編譯器相同),最終 **執行的匯編代碼都是運行時產生的** > 藉此無法透過下定斷點來暫停程式,所以需要設置此值 ::: 4. 移除 `Before launch` 中的 `Build` > ![](https://hackmd.io/_uploads/Hklj-u_pn.png) ### CLion 調適 JDK - compile-commands * 在 jdk 編譯完成(完成 `make`、`make images`)後,使用 CLion 開啟 JDK 調適還有另一種方法([**參考**](https://blog.jetbrains.com/clion/2020/03/openjdk-with-clion/)) 1. 執行以下指令 **產生 `compile_commands.json` 檔案** ```shell= make compile-commands ``` :::danger * **並不是每一版本的 JDK 都有這個指令**,我目前是切換到 **jdk-12+33** TAG 上 ::: 2. **使用 CLion 開啟 `compile_commands.json` 檔案** > ![](https://hackmd.io/_uploads/rJTJ6tu6h.png) 3. 執行 `Tools` -> `Compilation Database` -> `Change Project Root` 功能,**切換專案根目錄** > 切換到原 `jdk` 目錄 4. **建立 `Custom Build Targets`**:**設置 Build、Clean 工具** > ![](https://hackmd.io/_uploads/By78Rtda2.png) * **Build 工具設置** | 欄位 | 設定 | | - | - | | name | `linux_x86_64-server-fastdebug_make` | | Program | `make` | | Arguments | `CONF=linux-x86_64-server-fastdebug make` | | Working directory(jdk 位置) | `/home/alien/docker/downloadJDK/jdk_github/jdk` | > ![](https://hackmd.io/_uploads/rkrNxAWA2.png) * **Clean 工具設置** | 欄位 | 設定 | | - | - | | name | `linux_x86_64-server-fastdebug_clean` | | Program | `make` | | Arguments | `CONF=linux-x86_64-server-fastdebug clean` | | Working directory(jdk 位置) | `/home/alien/docker/downloadJDK/jdk_github/jdk` | > ![](https://hackmd.io/_uploads/H1R50FuT2.png) 5. **建立 `Custom Build Application`**: 同樣設置 `Executable`、`target`、`Program argument`... 等等資訊,並移除預設的 `Build launch` 的 `Build` 選項 > ![](https://hackmd.io/_uploads/rJ-g19_62.png) * 設置完後運行 JDK,就可以看到程式的運行式 > 下圖是 `java` 指令的入口:`java.c`#`JavaMain` > > ![](https://hackmd.io/_uploads/rkHgEq_63.png) ### CLion - Signal: SIGSEGV 錯誤 * 使用 CLion 調適 JDK 時有 **發生 `Signal: SIGSEGV` 錯誤**,這是因為 Ubuntu 預設使用 GNU 幫 C、C++ 進行編譯,所以會產生這個錯誤 所以須做以下 1. 在 `home` 目錄下創建 `.gdbinit` 文件 ```shell= touch ~/.gdbinit ``` 2. 編輯 `.gdbinit` 文件,並撰寫內容 ```shell= # 編譯 .gdbinit 檔案 vim ~/.gdbinit # 以下為內容 handle SIGSEGV pass noprint nostop handle SIGBUS pass noprint nostop ``` > ![](https://hackmd.io/_uploads/HJsNuddph.png) ## Appendix & FAQ :::info [**JDK 參考**](https://juejin.cn/post/7068473519415230495) ::: ###### tags: `JVM`