java性能優(yōu)化之代碼緩存優(yōu)化
JIT編譯器版本
JIT編譯器有不同的版本,而最終你使用哪種,取決于你所使用的系統(tǒng)平臺(tái)。前面的文章我們說到編譯器有-client和-server,
具體劃分應(yīng)該是如下所示:
-client32位client編譯器-server32位server編譯器-d6464位server編譯器
如果你的系統(tǒng)是32位,那么你只能使用32位JVM,如果你是64位系統(tǒng),那么可以選擇32位或64位系統(tǒng)。
不同jvm的編譯器版本如下:
| jvm版本 | -client | -server | -d64 |
|---|---|---|---|
| linux 32位 | 32位client | 32位server | 出錯(cuò) |
| linux 64位 | 64位server | 64位server | 64位server |
| windows 32位 | 32位client | 32位server | 出錯(cuò) |
| windows 64位 | 64位server | 64位server | 64位server |
| macOS | 64位server | 64位server | 64位server |
我們使用的java8,默認(rèn)使用的都是server編譯器,同時(shí)是開啟分層編譯的。
默認(rèn)情況JVM如何選擇編譯器?
假如我們沒有指定編譯器的參數(shù),那么JVM是如何選擇使用何種編譯器的呢?
實(shí)際上jvm是考慮機(jī)器的CPU數(shù)目:
- 在64位系統(tǒng),無論機(jī)器多少CPU,都會(huì)使用server編譯器
- 在32系統(tǒng)
- 如果只有一個(gè)cpu,那么使用client編譯器
- 多個(gè)cpu,使用server編譯器。
如何判斷當(dāng)前環(huán)境jvm使用的編譯器?
我們最經(jīng)常使用的查看java版本命令,就可以在最后一行展示當(dāng)前所使用的編譯器類型:
[root@public-server9 esmp]# java -version java version "1.8.0_172" Java(TM) SE Runtime Environment (build 1.8.0_172-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)
如上所示,Linux環(huán)境下使用的是64位server編譯器。
小節(jié):
不同的平臺(tái)環(huán)境對(duì)應(yīng)著不同的java版本,不同的java版本又對(duì)應(yīng)著不同的編譯器版本。我們?cè)谑褂玫臅r(shí)候,只需要選擇對(duì)應(yīng)于平臺(tái)的java版本,不需要手動(dòng)指定編譯器,仰仗于平臺(tái)所支持的編譯器即可。
常規(guī)的調(diào)優(yōu)可能就是選擇不同的編譯器版本,開放分層編譯等。本章,將會(huì)具體分析除此以外的編譯器優(yōu)化場(chǎng)景。
代碼緩存
JVM在編譯代碼后,會(huì)在代碼緩存當(dāng)中保存編譯后的匯編語言指令集。而代碼緩存的大小是固定的,換句話說,jvm能夠編譯的代碼數(shù)量就是固定的。
前面我們提到過,如果沒有被編譯成匯編語言的代碼,會(huì)通過解釋執(zhí)行的方式去運(yùn)行,性能會(huì)大幅下降。所以如何控制代碼緩存的大小,是一個(gè)我們可以優(yōu)化的點(diǎn)。
代碼緩存占滿發(fā)生在什么情況?
通常在使用client編譯器時(shí),會(huì)占用大量的代碼緩存,因?yàn)槠湓谶\(yùn)行過程中需要編譯的代碼非常多。相反,server編譯器采用優(yōu)先編譯的方式,運(yùn)行時(shí)只會(huì)對(duì)熱點(diǎn)代碼進(jìn)行編譯,所以發(fā)生代碼緩存占滿的情況較少。綜上所述,在使用分層編譯的時(shí)候,也有一定的可能存在代碼緩存被占滿的情況。
代碼緩存默認(rèn)大小
代碼緩存在不同版本的java當(dāng)中,默認(rèn)代碼緩存大小也不相同,如下僅展示java7和java8的部分:
| java版本 | 編譯器類型 | 代碼緩存大?。∕B) |
|---|---|---|
| java7 | 32位 client | 32 |
| java7 | 32位 server | 32 |
| java7 | 32位 server 分層編譯 | 48 |
| java8 | 32位 client | 32 |
| java8 | 32位 server 分層編譯 | 240 |
| java8 | 64位 server 分層編譯 | 240 |
如上可以發(fā)現(xiàn),java7的代碼緩存較小,比較容易出現(xiàn)問題。這也是為什么java7沒有默認(rèn)開啟分層編譯,而java8則默認(rèn)開啟。
我們可以通過下面的命令查看當(dāng)前代碼緩存的大小,我這里是java8:
[root@hecs-402944 opt]# jps 14186 Jps 1434 jar 655 WrapperSimpleApp [root@hecs-402944 opt]# jinfo -flag ReservedCodeCacheSize 1434 -XX:ReservedCodeCacheSize=251658240
251658240是字節(jié),換算后剛好240M。
如何確定正好的代碼緩存?
其實(shí)這個(gè)需要根據(jù)使用情況進(jìn)行實(shí)際調(diào)整,通過ReservedCodeCacheSize可以指定大小。
但是代碼緩存的大小的設(shè)置要考慮到服務(wù)器實(shí)際內(nèi)存的大小。如果我們將其分配過大,則這部分空間會(huì)被jvm預(yù)留出來,請(qǐng)確定你的服務(wù)器是否有足夠大的內(nèi)存。
另一個(gè)方面,32位的jvm被允許使用的最大內(nèi)存為4g,其中還包括堆內(nèi)存,元空間,棧,以及本地方法等等,所以代碼緩存總是會(huì)被限制大小的。
在64位機(jī)器也不是越大越好,每個(gè)機(jī)器上的進(jìn)程有自己的最大內(nèi)存空間,超過它也是沒有效果的。
綜上所述,有些大型應(yīng)用就需要我們對(duì)代碼緩存進(jìn)行調(diào)優(yōu)。
如何監(jiān)控代碼緩存?
前面我們學(xué)習(xí)過jconsole的使用,如果你的服務(wù)允許開啟jmx服務(wù)的話,那么就可以進(jìn)行監(jiān)控了,文章地址如下:java性能分析jconsole詳解
如下圖所示,就是監(jiān)控代碼緩存的動(dòng)態(tài)圖標(biāo):

我們可以根據(jù)監(jiān)控的結(jié)果去調(diào)整自己服務(wù)的代碼緩存大小,我這個(gè)服務(wù)舉例默認(rèn)的240M還有很大的差距,其實(shí)是不需要進(jìn)行調(diào)優(yōu)的。
到此這篇關(guān)于java性能優(yōu)化之代碼緩存優(yōu)化的文章就介紹到這了,更多相關(guān)java 代碼緩存優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合Jasypt實(shí)現(xiàn)配置加密的步驟詳解
Jasypt是一個(gè)Java庫,提供了一種簡(jiǎn)單的加密解密方式,可用于保護(hù)敏感數(shù)據(jù),例如密碼、API密鑰和數(shù)據(jù)庫連接信息等,本文給大家介紹了SpringBoot整合Jasypt實(shí)現(xiàn)配置加密的詳細(xì)步驟,感興趣的同學(xué)可以參考一下2023-11-11
Springboot 讀取 yml 配置文件里的參數(shù)值
本文主要介紹了Springboot 讀取 yml 配置文件里的參數(shù)值,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
Springboot如何通過filter修改Header的值
這篇文章主要介紹了Springboot如何通過filter修改Header的值問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Spring?Boot?多數(shù)據(jù)源處理事務(wù)的思路詳解
這篇文章主要介紹了Spring?Boot?多數(shù)據(jù)源如何處理事務(wù),本文單純就是技術(shù)探討,要從實(shí)際應(yīng)用中來說的話,我并不建議這樣去玩分布式事務(wù)、也不建議這樣去玩多數(shù)據(jù)源,畢竟分布式事務(wù)主要還是用在微服務(wù)場(chǎng)景下,對(duì)Spring?Boot?多數(shù)據(jù)源事務(wù)相關(guān)知識(shí)感興趣的朋友參考下本文2022-06-06
JNI實(shí)現(xiàn)最簡(jiǎn)單的JAVA調(diào)用C/C++代碼
這篇文章主要介紹了JNI實(shí)現(xiàn)最簡(jiǎn)單的JAVA調(diào)用C/C++代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
使用GSON庫轉(zhuǎn)換Java對(duì)象為JSON對(duì)象的進(jìn)階實(shí)例詳解
這篇文章主要介紹了使用GSON庫轉(zhuǎn)換Java對(duì)象為JSON對(duì)象的進(jìn)階實(shí)例詳解,包括注冊(cè)TypeAdapter及處理Enum類型等實(shí)際運(yùn)用中可能遇到的一些復(fù)雜問題,需要的朋友可以參考下2016-06-06
MyBatis中select語句中使用String[]數(shù)組作為參數(shù)的操作方法
在 MyBatis 中,如何在 mapper.xml 配置文件中 select 語句中使用 String[] 數(shù)組作為參數(shù)呢,并且使用IN關(guān)鍵字來匹配數(shù)據(jù)庫中的記錄,這篇文章主要介紹了MyBatis中select語句中使用String[]數(shù)組作為參數(shù),需要的朋友可以參考下2023-12-12
詳解Java synchronized關(guān)鍵字的用法
在多線程編程中常常使用鎖機(jī)制來確保同一時(shí)刻只有一個(gè)線程能夠修改共享內(nèi)存,在Java中一般是使用synchronized作為鎖機(jī)制,下面就讓我們來學(xué)習(xí)一下如何使用synchronized實(shí)現(xiàn)線程安全吧2023-08-08

