中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

wordpress金融網(wǎng)站模板廣告推廣費(fèi)用

wordpress金融網(wǎng)站模板,廣告推廣費(fèi)用,吉林省建設(shè)安全信息網(wǎng)官網(wǎng),遼寧省建設(shè)工程信息網(wǎng)專家?guī)煸趺慈氪斯P記來至于 黑馬程序員 內(nèi)存調(diào)優(yōu) 內(nèi)存溢出和內(nèi)存泄漏 內(nèi)存泄漏(memory leak):在Java中如果不再使用一個(gè)對(duì)象,但是該對(duì)象依然在 GC ROOT 的引用鏈上,這個(gè)對(duì)象就不會(huì)被垃圾回收器回收,這種情況就稱之為內(nèi)…

此筆記來至于 黑馬程序員

image-20241011150518298

內(nèi)存調(diào)優(yōu)

內(nèi)存溢出和內(nèi)存泄漏

  • 內(nèi)存泄漏(memory leak):在Java中如果不再使用一個(gè)對(duì)象,但是該對(duì)象依然在 GC ROOT 的引用鏈上,這個(gè)對(duì)象就不會(huì)被垃圾回收器回收,這種情況就稱之為內(nèi)存泄漏。
  • 內(nèi)存泄漏絕大多數(shù)情況都是由堆內(nèi)存泄漏引起的,所以后續(xù)沒有特別說明則討論的都是堆內(nèi)存泄漏。
  • 少量的內(nèi)存泄漏可以容忍,但是如果發(fā)生持續(xù)的內(nèi)存泄漏,就像滾雪球雪球越滾越大,不管有多大的內(nèi)存遲早會(huì)被消耗完,最終導(dǎo)致的結(jié)果就是內(nèi)存溢出。但是產(chǎn)生內(nèi)存溢出并不是只有內(nèi)存泄漏這一種原因

image-20241011151333653

image-20241011152029780

  • 內(nèi)存泄漏導(dǎo)致溢出的常見場(chǎng)景是大型的 Java后端應(yīng)用 中,在處理用戶的請(qǐng)求之后,沒有及時(shí)將用戶的數(shù)據(jù)刪除。隨著用戶請(qǐng)求數(shù)量越來越多,內(nèi)存泄漏的對(duì)象占滿了堆內(nèi)存最終導(dǎo)致內(nèi)存溢出。
  • 這種產(chǎn)生的內(nèi)存溢出會(huì)直接導(dǎo)致用戶請(qǐng)求無法處理,影響用戶的正常使用。重啟可以恢復(fù)應(yīng)用使用,但是在運(yùn)行一段時(shí)間之后依然會(huì)出現(xiàn)內(nèi)存溢出
  • 第二種常見場(chǎng)景是 分布式任務(wù)調(diào)度系統(tǒng)如 Elastic-job、Quartz 等進(jìn)行任務(wù)調(diào)度時(shí),被調(diào)度的 Java應(yīng)用 在調(diào)度任務(wù)結(jié)束中出現(xiàn)了內(nèi)存泄漏,最終導(dǎo)致多次調(diào)度之后內(nèi)存溢出。
  • 這種產(chǎn)生的內(nèi)存溢出會(huì)導(dǎo)致應(yīng)用執(zhí)行下次的調(diào)度任務(wù)執(zhí)行**。同樣重啟可以恢復(fù)應(yīng)用使用,但是在調(diào)度執(zhí)行一段時(shí)間之后依然會(huì)出現(xiàn)內(nèi)存溢出。**

解決內(nèi)存溢出的方法

image-20241011161821552

發(fā)現(xiàn)問題 - Top 命令
  • top命令 是 linux 下用來查看系統(tǒng)信息的一個(gè)命令,它提供給我們?nèi)?shí)時(shí)地去查看系統(tǒng)的資源,比如執(zhí)行時(shí)的進(jìn)程、線程和系統(tǒng)參數(shù)等信息。
  • 進(jìn)程使用的內(nèi)存為 RES(常駐內(nèi)存)- SHR(共享內(nèi)存)

image-20241011162105848

發(fā)現(xiàn)問題 - VisualVM
  • VisualVM是多功能合一的 Java故障排除工具 并且他是一款 可視化工具,整合了 命令行JDK工具 和 輕量級(jí)分析功能,功能非常強(qiáng)大。
  • 這款軟件在 Oracle JDK 6~8 中發(fā)布,但是在 Oracle JDK 9 之后不在JDk安裝目錄下需要單獨(dú)下載。
  • 下載地址:https://visualvm.github.io/
云服務(wù)器配置

image-20241011164325281

image-20241011164429775

只能用于測(cè)試環(huán)境,因?yàn)闀?huì)有 STW 影響用戶體驗(yàn)

發(fā)現(xiàn)問題- Arthas
  • Arthas 是一款線上監(jiān)控診斷產(chǎn)品,通過全局視角實(shí)時(shí)查看 應(yīng)用load、內(nèi)存、gc、線程 的狀態(tài)信息,**并能在不修改應(yīng)用代碼的情況下,對(duì)業(yè)務(wù)問題進(jìn)行診斷,**包括查看方法調(diào)用的出入?yún)?、異?#xff0c;監(jiān)測(cè)方法執(zhí)行耗時(shí),類加載信息等,大大提升線上問題排查效率。

image-20241011164706550

image-20241011164912911

發(fā)現(xiàn)問題 - Prometheus + Grafana
  • Prometheus + Grafana 是企業(yè)中運(yùn)維常用的監(jiān)控方案,其中 Prometheus 用來采集系統(tǒng)或者應(yīng)用的相關(guān)數(shù)據(jù),同時(shí)具備告警功能。Grafana 可以將 Prometheus 采集到的數(shù)據(jù)以可視化的方式進(jìn)行展示。
  • Java程序員 要學(xué)會(huì)如何讀懂 Grafana 展示的 Java虛擬機(jī) 相關(guān)的參數(shù)。

image-20241011165939158

image-20241011171029053

發(fā)現(xiàn)問題 - 堆內(nèi)存狀況的對(duì)比

image-20241011171444574

產(chǎn)生內(nèi)存溢出原因一:代碼中的內(nèi)存泄漏(壓力測(cè)試)

image-20241011171534308

equals() 和 hashcode() 導(dǎo)致的內(nèi)存泄漏

1、以 JDK8 為例,首先調(diào)用 hash方法 計(jì)算 key 的哈希值,hash方法 中會(huì)使用到 key的 hashcode方法。根據(jù) hash方法 的結(jié)果決定存放的數(shù)組中位置。
2、如果沒有元素,直接放入。如果有元素,先 判斷key 是否相等,會(huì)用到 equals方法,如果 key相等,直接替換value;key不相等,走鏈表或者紅黑樹查找邏輯,其中也會(huì)使用equals比對(duì)是否相同。

1、hashCode 方法實(shí)現(xiàn)不正確,會(huì)導(dǎo)致相同 id的學(xué)生對(duì)象計(jì)算出來的 hash值 不同,可能會(huì)被分到不同的槽中。
2、equals 方法實(shí)現(xiàn)不正確,會(huì) 導(dǎo)致key在 比對(duì)時(shí),即便學(xué)生對(duì)象的 id是相同的,也被認(rèn)為是 不同的key。
3、長(zhǎng)時(shí)間運(yùn)行之后 HashMap中會(huì) 保存大量相同id的學(xué)生 數(shù)據(jù)。

image-20241011174855774

image-20241011172728196

解決方案:

1、在定義新實(shí)體時(shí),始終重寫 equals() 和 hashCode() 方法。
2、重寫時(shí)一定要確定使用了唯一標(biāo)識(shí)去區(qū)分不同的對(duì)象,比如用戶的id等。
3、hashmap 使用時(shí)盡量使用編號(hào) id 等數(shù)據(jù)作為 key,不要將整個(gè)實(shí)體類對(duì)象作為 key存放。

案例2:內(nèi)部類引用外部類
  • 1、非靜態(tài)的內(nèi)部類默認(rèn)會(huì)持有外部類,盡管代碼上不再使用外部類,所以如果有地方引用了這個(gè)非靜態(tài)內(nèi)部類,會(huì)導(dǎo)致外部類也被引用,垃圾回收時(shí)無法回收這個(gè)外部類。
  • 2、匿名內(nèi)部類對(duì)象如果在非靜態(tài)方法中被創(chuàng)建,會(huì)持有調(diào)用者對(duì)象,垃圾回收時(shí)無法回收調(diào)用者。
public class Outer {private byte[] bytes = new byte[1024 * 1024]; // 外部類持有數(shù)據(jù)private String name = "測(cè)試";class Inner { // 改為靜態(tài)內(nèi)部類就好了 static class Innerprivate String name;public Inner() {this.name = Outer.this.name;}}public static void main(String[] args) throws IOException, InterruptedException {System.in.read();int count = 0;ArrayList<Inner> inners = new ArrayList<>();while (true) {if (count++ % 100 == 0) {Thread.sleep(10);}inners.add(new Outer().new Inner());}}
}

1、這個(gè)案例中,使用內(nèi)部類的原因是可以直接獲取到外部類中的成員變量值,簡(jiǎn)化開發(fā)。如果不想持有外部類對(duì)象,應(yīng)該使用靜態(tài)內(nèi)部類。
2、使用靜態(tài)方法,可以避免匿名內(nèi)部類持有調(diào)用者對(duì)象。

案例3:ThreadLocal 的使用

image-20241011185345312

import java.util.concurrent.*;public class Demo5 {public static ThreadLocal<Object> threadLocal = new ThreadLocal<>():public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(Integer.MAX_VALUE, Integer.MAX_VALUE,keepAliveTime:0,TimeUnit.DAYS, new SynchronousQueue<>());int count = 0;while (true) {System.out.println(++count);threadPlloExecutor.execute(() -> {threadPoolExecutor.set(new byte[1024 * 1024]);// threadLocal.remove();  線程池一定要釋放 threadPoolExecutor });}}
}
案例4:String 的 intern 方法

image-20241011190129392

import java.util.ArrayList;
import java.util.List;public class Demo6_2 {public static void main(String[] args) {List<String> list = new ArrayList<String>();int i = 0;while (true) {// String.valueOf(i++).intern(); // JDK1.6 perm gen 不會(huì)溢出list.add(String.valueOf(i++).intern()); // 溢出}}
}
案例5:通過靜態(tài)字段保存對(duì)象

image-20241011191401993

import java.time.Duration;public class CaffineDemo {public static void main(String[] args) throws InterruptedException {Cache<Object, Object> build = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(100)).build();int count = 0;while (true) {build.put(count++, new byte[1024 * 1024 * 10]);Thread.sleep(100L);}}
}

image-20241011192007708

產(chǎn)生內(nèi)存溢出原因二:并發(fā)請(qǐng)求問題
  • 并發(fā)請(qǐng)求問題指的是用戶通過發(fā)送請(qǐng)求 向 Java應(yīng)用 獲取數(shù)據(jù),正常情況下 Java應(yīng)用將數(shù)據(jù)返回之后,這部分?jǐn)?shù)據(jù)就可以在內(nèi)存中被釋放掉。

  • 并發(fā)請(qǐng)求問題指的是用戶通過發(fā)送請(qǐng)求向 Java應(yīng)用獲取數(shù)據(jù),正常情況下 Java應(yīng)用 將數(shù)據(jù)返回之后,這部分?jǐn)?shù)據(jù)就可以在內(nèi)存中被釋放掉。**但是由于用戶的并發(fā)請(qǐng)求量有可能很大,同時(shí)處理數(shù)據(jù)的時(shí)間很長(zhǎng),導(dǎo)致大量的數(shù)據(jù)存在于內(nèi)存中,最終超過了內(nèi)存的上限,導(dǎo)致內(nèi)存溢出。**這類問題的處理思路和內(nèi)存泄漏類似,首先要定位到對(duì)象產(chǎn)生的根源。

image-20241011192945175

使用 Jmeter 進(jìn)行并發(fā)測(cè)試,發(fā)現(xiàn)內(nèi)存溢出問題

image-20241011193030224

診斷-內(nèi)存快照

  • 當(dāng)堆內(nèi)存溢出時(shí),需要在堆內(nèi)存溢出時(shí)將整個(gè)堆內(nèi)存保存下來,生成內(nèi)存快照(HeapProfile)文件

  • 使用 MAT打開 hprof文件,并選擇內(nèi)存泄漏檢測(cè)功能,MAT 會(huì)自行根據(jù)內(nèi)存快照中保存的數(shù)據(jù)分析內(nèi)存泄源的根源。

  • 生成內(nèi)存快照的 Java虛擬機(jī) 參數(shù):
    -XX:+HeapDumpOnOutOfMemoryError:發(fā)生 OutOfMemoryError 錯(cuò)誤時(shí),自動(dòng)生成 hprof 內(nèi)存快照文件。
    -XX:HeapDumpPath = :指定 hprof文件 的輸出路徑。

MAT 內(nèi)存泄漏檢測(cè)的原理-支配樹
  • MAT 提供了稱為 **支配樹(DominatorTree)**的對(duì)象圖。支配樹展示的是對(duì)象實(shí)例間的支配關(guān)系。在對(duì)象引用圖中,所有指向?qū)ο驜的路徑都經(jīng)過對(duì)象A,則認(rèn)為 對(duì)象A 支配 對(duì)象B。

image-20241011202742562

MAT 內(nèi)存泄漏檢測(cè)的原理-深堆和淺堆

image-20241011211241696

image-20241011211333872

// -XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=D:/jvm/heapdemo.hprof
public class HeapDemo {public static void main(String[] args) {TestClass a1 = new TestClass();TestClass a2 = new TestClass();TestClass a3 = new TestClass();String s1 = "itheima1";String s2 = "itheima2";String s3 = "itheima3";a1.list.add(s1);a2.list.add(s1);a2.list.add(s2);a3.list.add(s3);// System.out.print(ClassLayout.parseClass(TestClass.class).toPrintable());s1 = null;s2 = null;s3 = null;System.gc();}
}

image-20241011214825207

MAT 內(nèi)存泄漏檢測(cè)的原理

image-20241011215329321

導(dǎo)出運(yùn)行中系統(tǒng)的內(nèi)存快照并進(jìn)行分析

image-20241011215756900

分析超大堆的內(nèi)存快照
  • 在程序員開發(fā)用的機(jī)器內(nèi)存范圍之內(nèi)的快照文件,直接使用 MAT 打開分析即可。但是經(jīng)常會(huì)遇到服務(wù)器上的程序占用的內(nèi)存達(dá)到 10G以上,開發(fā)機(jī)無法正常打開此類內(nèi)存快照,此時(shí)需要下載服務(wù)器操作系統(tǒng)對(duì)應(yīng)的 MAT。 下載地址: https://eclipse.dev/mat/downloads.php

image-20241011221408384

案例實(shí)戰(zhàn)

image-20241011221724444

案例1-分頁(yè)查詢文章接口的內(nèi)存溢出

image-20241011221918900

image-20241011221852061

image-20241011223246327

案例2- Mybatis 導(dǎo)致的內(nèi)存溢出

image-20241011224532800

案例3 - 導(dǎo)出大文件內(nèi)存溢出

image-20241011224719174

image-20241011230057521

案例4- ThreadLocal 使用時(shí)占用大量?jī)?nèi)存

image-20241011230854575

image-20241011230823686

案例5-文章內(nèi)容審核接口的內(nèi)存問題

image-20241011230935004

image-20241011231121950

存在問題:

1、線程池參數(shù)設(shè)置不當(dāng),會(huì)導(dǎo)致大量線程的創(chuàng)建或者隊(duì)列中保存大量的數(shù)據(jù)。
2、任務(wù)沒有持久化,一旦走線程池的拒絕策略或者服務(wù)宕機(jī)、服務(wù)器掉電等情況很有可能會(huì)丟失任務(wù)。

image-20241011231709485

image-20241011232008891

image-20241011232134014

診斷和解決問題 兩種方案

image-20241011232252246

在線定位問題 -步驟

image-20241011232618809

1 在線定位問題 btrace

image-20241011233113483

官網(wǎng):https://github.com/btraceio/btrace/releases/latest

2、內(nèi)存溢出有哪幾種產(chǎn)生的原因?

1、持續(xù)的內(nèi)存泄漏:內(nèi)存泄漏持續(xù)發(fā)生,不可被回收同時(shí)不再使用的內(nèi)存越來越多就像滾雪球雪球越滾越大,最終內(nèi)存被消耗完無法分配更多的內(nèi)存取使用,導(dǎo)致內(nèi)存溢出。
2、并發(fā)請(qǐng)求問題:用戶通過發(fā)送請(qǐng)求向Java應(yīng)用獲取數(shù)據(jù),正常情況下Java應(yīng)用將數(shù)據(jù)返回之后,這部分?jǐn)?shù)據(jù)就可以在內(nèi)存中被釋放掉。但是由于用戶的并發(fā)請(qǐng)求量有可能很大,同時(shí)處理數(shù)據(jù)的時(shí)間很長(zhǎng),導(dǎo)致大量的數(shù)據(jù)存在于內(nèi)存中,最終超過了內(nèi)存的上限,導(dǎo)致內(nèi)存溢出。

3、解決內(nèi)存泄漏問題的方法是什么?

1、發(fā)現(xiàn)問題,,通過監(jiān)控工具盡可能盡早地發(fā)現(xiàn)內(nèi)存慢慢變大的現(xiàn)象。
2、診斷原因,通過分析內(nèi)存快照或者在線分析方法調(diào)用過程,診斷問題產(chǎn)生的根源,定位到出現(xiàn)問題的源代碼。
3、修復(fù)源代碼中的問題,如代碼bug、技術(shù)方案不合理、業(yè)務(wù)設(shè)計(jì)不合理等等。
4、在測(cè)試環(huán)境驗(yàn)證問題是否已經(jīng)解決,最后發(fā)布上線。

GC 調(diào)優(yōu)

GC調(diào)優(yōu) 指的是對(duì)**垃圾回收(Garbage Collection)**進(jìn)行調(diào)優(yōu)。GC調(diào)優(yōu)的主要目標(biāo)是避免由垃圾回收引起程序性能下降。

GC調(diào)優(yōu)的核心分成三部分:
1、通用 Jvm參數(shù) 的設(shè)置。
2、特定垃圾回收器的 Jvm參數(shù)的設(shè)置。
3、解決由頻繁的 FULL GC 引起的程序性能問題。

GC調(diào)優(yōu)沒有沒有唯一的標(biāo)準(zhǔn)答案,如何調(diào)優(yōu)與硬件、程序本身、使用情況均有關(guān)系,重點(diǎn)學(xué)習(xí)調(diào)優(yōu)的工具和方法。

GC調(diào)優(yōu)的核心指標(biāo)

所以判斷 GC 是否需要調(diào)優(yōu),需要從三方面來考慮,與 GC算法 的評(píng)判標(biāo)準(zhǔn)類似:
1.吞吐量(Throughput)吞吐量分為業(yè)務(wù)吞吐量和垃圾回收吞吐量
業(yè)務(wù)吞吐量 指的在一段時(shí)間內(nèi),程序需要完成的業(yè)務(wù)數(shù)量。比如企業(yè)中對(duì)于吞吐量的要求可能會(huì)是這樣的:

  • 支持用戶每天生成10000筆訂單
  • 在晚上8點(diǎn)到10點(diǎn),支持用戶查詢50000條商品信息

GC調(diào)優(yōu) 的方法

保證高吞吐量的常規(guī)手段有兩條:

1、優(yōu)化業(yè)務(wù)執(zhí)行性能,減少單次業(yè)務(wù)的執(zhí)行時(shí)間
2、優(yōu)化垃圾回收吞吐量

image-20241011235212818

image-20241011235255462

image-20241011235403878

3.內(nèi)存使用量

內(nèi)存使用量指的是 Java應(yīng)用 占用系統(tǒng)內(nèi)存的最大值,一般通過 Jvm參數(shù)調(diào)整,在滿足上述兩個(gè)指標(biāo)的前提下,這個(gè)值越小越好。

image-20241011235513666

發(fā)現(xiàn)問題頁(yè)- jstat 工具
  • Jstat工具 是 JDK 自帶的一款監(jiān)控工具,可以提供各種垃圾回收、類加載、編譯信息等不同的數(shù)據(jù)。
  • 使用方法為:jstat-gc 進(jìn)程ID 每次統(tǒng)計(jì)的間隔 (毫秒) 統(tǒng)計(jì)次數(shù)

image-20241011235900009

發(fā)現(xiàn)問題- visualvm插 件
  • VisualVm 中提供了一款 visualTool 插件,實(shí)時(shí)監(jiān)控 Java進(jìn)程 的堆內(nèi)存結(jié)構(gòu),堆內(nèi)存變化趨勢(shì)以及垃圾回收時(shí)間的變化趨勢(shì)。同時(shí)還可以監(jiān)控對(duì)象晉升的直方圖。

image-20241012000022885

Prometheus + Grafana
  • Prometheus + Grafana 是企業(yè)中運(yùn)維常用的監(jiān)控方案,其中 Prometheus用來采集系統(tǒng)或者應(yīng)用的相關(guān)數(shù)據(jù),同時(shí)具備告警功能。Grafana 可以將 Prometheus 采集到的數(shù)據(jù)以可視化的方式進(jìn)行展示。
  • Java程序員要學(xué)會(huì)如何讀懂 Grafana展示 的 Java虛擬機(jī) 相關(guān)的參數(shù)。

image-20241012000336691

發(fā)現(xiàn)問題 -GC 日志
  • 通過 GC日志,可以更好的看到垃圾回收細(xì)節(jié)上的數(shù)據(jù),同時(shí)也可以根據(jù)每款垃圾回收器的不同特點(diǎn)更好地發(fā)現(xiàn)存在的問題。
  • 使用方法(JDK 8及以下):-XX:+PrintGCDetails -Xloggc:文件名
  • 使用方法(JDK 9+):-Xlog:gc*:file=文件名

image-20241012001414831

發(fā)現(xiàn)問題 - GC Viewer
  • GC Viewer 是一個(gè)將 GC日志 轉(zhuǎn)換成可視化圖表的小工具

    github 地址: https://github.com/chewiebug/GcViewer

  • 使用方法:java-jar gcviewer_1.3.4.jar 日志文件.log

image-20241012001703938

發(fā)現(xiàn)問題 - GCeasy
  • GCeaSy是業(yè)界首款使用 AI機(jī)器學(xué)習(xí)技術(shù) 在線進(jìn)行 GC分析 和 診斷的工具。定位內(nèi)存泄漏、GC延遲高 的問題,提供 JVM參數(shù)優(yōu)化建議,支持在線的可視化工具圖表展示。

    官方網(wǎng)站:https://gceasy.io/

image-20241012002543353

發(fā)現(xiàn)問題 - 常見的 GC模式
一、正常情況

特點(diǎn):呈現(xiàn)鋸齒狀,對(duì)象創(chuàng)建之后內(nèi)存上升,一旦發(fā)生垃圾回收之后下降到底部,并且每次下降之后的內(nèi)存大小接近,存留的對(duì)象較少。

image-20241012094955440

二、緩存對(duì)象過多

特點(diǎn):呈現(xiàn)鋸齒狀,對(duì)象創(chuàng)建之后內(nèi)存上升,一旦發(fā)生垃圾回收之后下降到底部,并且每次下降之后的內(nèi)存大小接近,處于比較高的位置。
問題產(chǎn)生原因:程序中保存了大量的緩存對(duì)象,導(dǎo)致 GC 之后無法釋放,可以使用 MAT 或者 HeapHero等工具 進(jìn)行分析內(nèi)存占用的原因。

image-20241012095108175

三、內(nèi)存泄漏

特點(diǎn):呈現(xiàn)鋸齒狀,每次垃圾回收之后下降到的內(nèi)存位置越來越高,最后由于垃圾回收無法釋放空間導(dǎo)致對(duì)象無法分配產(chǎn)生 outOfMemory 的錯(cuò)誤。
問題產(chǎn)生原因:程序中保存了大量的內(nèi)存泄漏對(duì)象,導(dǎo)致 GC 之后無法釋放,可以使用 MAT 或者 HeapHero等工具 進(jìn)行分析是哪些對(duì)象產(chǎn)生了內(nèi)存泄漏。

image-20241012095138087

四、持續(xù)的 Fu GC

特點(diǎn):在某個(gè)時(shí)間點(diǎn)產(chǎn)生多次 FULL GC,CPU使用率 同時(shí)飆高,用戶請(qǐng)求基本無法處理。一段時(shí)間之后恢復(fù)正常。問題產(chǎn)生原因:在該時(shí)間范圍請(qǐng)求量激增,程序開始生成更多對(duì)象,同時(shí) 垃圾收集 無法跟上對(duì)象創(chuàng)建速率,導(dǎo)致持續(xù)地在進(jìn)行 FULL GC。GC分析報(bào)告

image-20241012095207463

五、元空間不足導(dǎo)致的 FULL GC

特點(diǎn):堆內(nèi)存的大小并不是特別大,但是持續(xù)發(fā)生 FULL GC。問題產(chǎn)生原因:元空間大小不足,導(dǎo)致持續(xù) FULL GC 回收元空間的數(shù)據(jù)。GC分析報(bào)告

image-20241012095921960

解決 GC 問題的手段

解決GC問題的手段中,前三種是比較推薦的手段,第四種僅在前三種無法解決時(shí)選用:

image-20241012100032580

解決問題 -優(yōu)化基礎(chǔ) JVM參數(shù)
參數(shù)1:-Xmx 和-Xms

-Xmx 參數(shù)設(shè)置的是**最大堆內(nèi)存,**但是由于程序是運(yùn)行在服務(wù)器或者容器上,計(jì)算可用內(nèi)存時(shí),要將元空間、操作系統(tǒng)、其它軟件占用的內(nèi)存排除掉。

  • 案例:服務(wù)器內(nèi)存 4G,操作系統(tǒng)+元空間最大值+其它軟件占用 1.5G,-Xmx可以設(shè)置為 2g。最合理的設(shè)置方式應(yīng)該是根據(jù)最大并發(fā)量估算服務(wù)器的配置,然后再根據(jù)服務(wù)器配置計(jì)算最大堆內(nèi)存的值。

image-20241012100423088

參數(shù)1:-Xmx 和-Xms
  • -Xms用來設(shè)置初始堆大小,建議將-Xms設(shè)置的和-Xmx一樣大,有以下幾點(diǎn)好處:

    1. 運(yùn)行時(shí)性能更好,堆的擴(kuò)容是需要向操作系統(tǒng)申請(qǐng)內(nèi)存的,這樣會(huì)導(dǎo)致程序性能短期下降。
    2. 可用性問題,如果在擴(kuò)容時(shí)其他程序正在使用大量?jī)?nèi)存,很容易因?yàn)椴僮飨到y(tǒng)內(nèi)存不足分配失敗。
    3. 啟動(dòng)速度更快,Oracle官方文檔的原話:如果初始堆太小,Java應(yīng)用程序啟動(dòng)會(huì)變得很慢,因?yàn)?JVM 被迫頻繁執(zhí)行垃圾收集,直到堆增長(zhǎng)到更合理的大小。為了獲得最佳啟動(dòng)性能,請(qǐng)將初始堆大小設(shè)置為與最大堆大小相同。
  • 參數(shù)2 :-XX:MaxMetaspaceSize 和 -XX:MetaspaceSize

    • -XX:MaxMetaspaceSize=值 參數(shù)指的是最大元空間大小,默認(rèn)值比較大,如果出現(xiàn)元空間內(nèi)存泄漏會(huì)讓操作系統(tǒng)可用內(nèi)存不可控,建議根據(jù)測(cè)試情況設(shè)置最大值,一般設(shè)置為 256m。
    • -XX:MetaspaceSize=值 參數(shù)指的是到達(dá)這個(gè)值之后會(huì)觸發(fā)FULL GC(網(wǎng)上很多文章的初始元空間大小是錯(cuò)誤的)后續(xù)什么時(shí)候再觸發(fā) JVM 會(huì)自行計(jì)算。如果設(shè)置為和 MaxMetaspaceSize 一樣大,就不會(huì) FULL GC,但是對(duì)象也無法回收。

image-20241012101010384

參數(shù)3:-Xss虛擬機(jī)棧大小

如果我們不指定棧的大小,JVM 將創(chuàng)建一個(gè)具有默認(rèn)大小的棧。大小取決于操作系統(tǒng)和計(jì)算機(jī)的體系結(jié)構(gòu)。
比如 Linu×x86 64位:1MB,如果不需要用到這么大的棧內(nèi)存,完全可以將此值調(diào)小節(jié)省內(nèi)存空間,合理值為256k - 1m之間。
使用:-Xss 256k

參數(shù)4:不建議手動(dòng)設(shè)置的參數(shù)

由 于JVM底層 設(shè)計(jì)極為復(fù)雜,一個(gè)參數(shù)的調(diào)整也許讓某個(gè)接口得益,但同樣有可能影響其他更多接口。
-Xmn 年輕代的大小,默認(rèn)值為整個(gè)堆的 1/3,可以根據(jù)峰值流量計(jì)算最大的年輕代大小,盡量讓對(duì)象只存放在年輕代,不進(jìn)入老年代。但是實(shí)際的場(chǎng)景中,接口的響應(yīng)時(shí)間、創(chuàng)建對(duì)象的大小、程序內(nèi)部還會(huì)有一些定時(shí)任務(wù)等不確定因素都會(huì)導(dǎo)致這個(gè)值的大小并不能僅憑計(jì)算得出,如果設(shè)置該值要進(jìn)行大量的測(cè)試。G1垃圾回收器盡量不要設(shè)置該值,G1會(huì)動(dòng)態(tài)調(diào)整年輕代的大小。

image-20241012101400184

-XX:SurvivorRatio 伊甸園區(qū)和幸存者區(qū)的大小比例,默認(rèn)值為8。
-XX:MaxTenuringThreshold 最大晉升閾值,年齡大于此值之后,會(huì)進(jìn)入老年代。另外 JVM 有動(dòng)態(tài)年齡判斷機(jī)制:將年齡從小到大的對(duì)象占據(jù)的空間加起來,如果大于 survivor 區(qū)域的 50%,然后把等于或大于該年齡的對(duì)象,放入到老年代。

image-20241012101641612

-XX:+DisableExplicitGC

禁止在代碼中使用system·gc(), System·gc() 可能會(huì)引起FULL GC,在代碼中盡量不要使用。使用 DisableExplicitGC參數(shù) 可以禁止使用 system.gc() 方法調(diào)用。

  • -XX:+HeapDumpOnOutOfMemoryError:發(fā)生 outofMemoryError錯(cuò)誤 時(shí),自動(dòng)生成 hprof內(nèi)存快照文件。
    -XX:HeapDumpPath= :指定hprof文件的輸出路徑。
打印 GC 日志

JDK8及之前:-XX:+PrintGCDetails -XX:+PrintGCDateStamps-Xloggc:文件路徑
JDK9及之后:-Xlog:gc*:file=文件路徑

image-20241012102056910

image-20241012102452337

解決問題優(yōu)化垃圾回收器的參數(shù)

這部分優(yōu)化效果未必出色,僅當(dāng)前邊的一些手動(dòng)無效時(shí)才考慮

一個(gè)優(yōu)化的案例:

CMS的 并發(fā)模式失敗(concurrentmodefailure)現(xiàn)象。由于 CMS 的垃圾清理線程和用戶線程是 并行進(jìn)行的,如果在并發(fā)清理的過程中老年代的空間不足以容納放入老年代的對(duì)象,會(huì)產(chǎn)生并發(fā)模式失敗。

并發(fā)模式失敗會(huì)導(dǎo)致 Java虛擬機(jī) 使用 Serial old單線程 進(jìn)行 FULL GC 回收老年代,出現(xiàn)長(zhǎng)時(shí)間的停頓。

image-20241012103938071

@RequestMapping("/fullgc")public class Demo2Controller {private Cache chche = Caffeine.newBuilder().weakKeys().softValues().build();private List<Object> objs = nwe ArrayList<>();private static final int _1MB = 1024 * 1024;// FULLGC 測(cè)試// -Xms8g -Xmx8g -Xss256k -XX:MaxMetaspaceSize=512m -XX:+DisableExplicitGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/test.hprof -verbose:gc -XX+PrintGCDetails -XX:PrintGCTimeStamps// ps + po 50并發(fā) 260ms 100并發(fā) 474 200并發(fā)930// cms -XX:UseParNewGC -XX:UseConcMarkSweepGC 50并發(fā) 157ms 200并發(fā) 833// g1 JDK11 并發(fā)200 248@GetMappin("/1")public void test() throws InterruptedException {cache.put(RandomStringUtils.randomAlphabetic(8), new byte[10 * _1MB]);}
}
解決方案:
  1. 減少對(duì)象的產(chǎn)生以及對(duì)象的晉升。
  2. 增加堆內(nèi)存大小
  3. 優(yōu)化垃圾回收器的參數(shù),比如 -XX:CMSInitiatingOccupancyFraction=值,當(dāng)老年代大小到達(dá)該閾值時(shí),會(huì)自動(dòng)進(jìn)行 CMS垃圾回收,通過控制這個(gè)參數(shù)提前進(jìn)行老年代的垃圾回收,減少其大小。
  4. JDK8中 默認(rèn)這個(gè)參數(shù)值為 -1,根據(jù)其他幾個(gè)參數(shù)計(jì)算出閾值:
    ((100 - MinHeapFreeRatio) + (double)(CMSTriggerRatio * MinHeapFreeRatio) / 100.0)
  5. 該參數(shù)設(shè)置完是不會(huì)生效的,必須開啟-XX:+UseCMSInitiatingOccupancyOnly參數(shù)。

image-20241012104852881

案例實(shí)戰(zhàn)

image-20241012104951543

image-20241012111403812

image-20241012111725586

image-20241012111752959

image-20241012111922027

image-20241012112340006

image-20241012114431163

性能調(diào)優(yōu)

應(yīng)用程序在運(yùn)行過程中經(jīng)常會(huì)出現(xiàn)性能問題,比較常見的性能問題現(xiàn)象是:

  1. 通過 top命令 查看 CPU占用率高,接近100甚至 多核CPU 下超過100 都是有可能的。
  2. 請(qǐng)求單個(gè)服務(wù)處理時(shí)間特別長(zhǎng),多服務(wù)使用 skywalking 等監(jiān)控系統(tǒng)來判斷是哪一個(gè)環(huán)節(jié)性能低下。
  3. 程序啟動(dòng)之后運(yùn)行正常,但是在運(yùn)行一段時(shí)間之后無法處理任何的請(qǐng)求**(內(nèi)存和GC正常)**

線程轉(zhuǎn)儲(chǔ)(Thread Dump)提供了對(duì)所有運(yùn)行中的線程當(dāng)前狀態(tài)的快照。線程轉(zhuǎn)儲(chǔ)可以通過 jstack、visualvm 等工具獲取。其中包含了線程名、優(yōu)先級(jí)、線程ID、線程狀態(tài)、線程棧信息等等內(nèi)容,可以用來解決CPU占用率高、死鎖等問題。

image-20241012115127955

線程轉(zhuǎn)儲(chǔ)者(Thread Dump)中的幾個(gè)核心內(nèi)容:

**名稱:**線程名稱,通過給線程設(shè)置合適的名稱更容易“見名知意”
優(yōu)先級(jí)(prio): 線程的優(yōu)先級(jí)
JavaID(tid): JVM 中線程的 唯一ID
本地ID(nid): 操作系統(tǒng) 分配給線程的 唯一ID
**狀態(tài):**線程的狀態(tài),分為:
NEW -新創(chuàng)建的線程,尚未開始執(zhí)行
RUNNABLE -正在運(yùn)行或準(zhǔn)備執(zhí)行
BLOCKED - 等待獲取監(jiān)視器鎖以進(jìn)入或重新進(jìn)入同步塊/方法
WAITING -等待其他線程執(zhí)行特定操作,沒有時(shí)間限制
TIMED_WAITING -等待其他線程在指定時(shí)間內(nèi)執(zhí)行特定操作
TERMINATED -已完成執(zhí)行

  • 棧追蹤:顯示整個(gè)方法的棧幀信息

    線程轉(zhuǎn)儲(chǔ)的可視化在線分析平臺(tái):
    1.https://jstack.review/
    2.https://fastthread.io/

案例1:CPU 占用率高問題的解決方案

image-20241012121841656

image-20241012121934850

image-20241012122010546

image-20241012122303010

image-20241012122336314

案例2:接口響應(yīng)時(shí)間很長(zhǎng)的問題

image-20241012122426168

Arthas 的 trace命令

使用 arthas 的 trace命令,可以展示出整個(gè)方法的調(diào)用路徑以及每一個(gè)方法的執(zhí)行耗時(shí)。
命令:trace 類名方法名

  • 添加–skipJDKMethod false 參數(shù)可以輸出 JDk核心 包中的方法及耗時(shí)。
  • 添加‘#cost 〉毫秒值’參數(shù),只會(huì)顯示耗時(shí)超過該毫秒值的調(diào)用。
  • 添加 -n 數(shù)值參數(shù),最多顯示該數(shù)值條數(shù)的數(shù)據(jù)。
  • 所有監(jiān)控都結(jié)束之后,輸入 stop 結(jié)束監(jiān)控,重置 arthas增強(qiáng)的對(duì)象。

image-20241012122629884

總結(jié):

1、通過 arthas的 trace命令,首先找到性能較差的具體方法,如果訪問量比較大,建議設(shè)置最小的耗時(shí),精確的找到耗時(shí)比較高的調(diào)用。
2、通過 watch命令,查看此調(diào)用的參數(shù)和返回值,重點(diǎn)是參數(shù),這樣就可以在開發(fā)環(huán)境或者測(cè)試環(huán)境模擬類似的現(xiàn)象,通過 debug 找到具體的問題根源。
3、使用 stop命令 將所有增強(qiáng)的對(duì)象恢復(fù)。

案例3:定位偏底層的性能問題

image-20241012123340608

Arthas 的 profile 命令

使用 arthas 的 profile 命令,生成性能監(jiān)控的火焰圖。
命令1: profiler start 開始監(jiān)控方法執(zhí)行性能
命令2: profiler stop – format html 以 HTML 的方式生成火焰圖
火焰圖中一般找綠色部分Java中棧頂上比較平的部分,很可能就是性能的瓶頸。

image-20241012123955994

image-20241012124326069

性能調(diào)優(yōu)解決的問題

應(yīng)用程序在運(yùn)行過程中經(jīng)常會(huì)出現(xiàn)性能問題,比較常見的性能問題現(xiàn)象是:

1、通過 top命令 查看 CPU占用率高,接近 100甚至 多核CPU下 超過 100都是 有可能的。
2、請(qǐng)求單個(gè)服務(wù)處理時(shí)間特別長(zhǎng),多服務(wù)使用 skywalking等監(jiān)控系統(tǒng) 來判斷是哪一個(gè)環(huán)節(jié)性能低下。
3、程序啟動(dòng)之后運(yùn)行正常,但是在運(yùn)行一段時(shí)間之后無法處理任何的請(qǐng)求(內(nèi)存和GC正常)。

案例4:線程被耗盡問題

image-20241012124557007

image-20241012124957199

image-20241012125114138

解決方案:

3、使用 fastthread 自動(dòng)檢測(cè)線程問題。https://fastthread.io/
Fastthread 和 Gceasy類似,是一款在線的Al自動(dòng)線程問題檢測(cè)工具,可以提供線程分析報(bào)告。通過報(bào)告查看是否存在死鎖問題。

image-20241012125216702

性能調(diào)優(yōu)的方法

image-20241012141003302

JIT 對(duì)程序性能的影響

Java 程序在運(yùn)行過程中,JIT 即時(shí)編譯器會(huì)實(shí)時(shí)對(duì)代碼進(jìn)行性能優(yōu)化,所以僅憑少量的測(cè)試是無法真實(shí)反應(yīng)運(yùn)行系統(tǒng)最終給用戶提供的性能。如下圖,隨著執(zhí)行次數(shù)的增加,程序性能會(huì)逐漸優(yōu)化。

image-20241012141142813

OpenJDK 中提供了一款叫 JMH(Java Microbenchmark Harness)的工具,可以準(zhǔn)確地對(duì) Java代碼 進(jìn)行基準(zhǔn)測(cè)試,量化方法的執(zhí)行性能。

官網(wǎng)地址:https://github.com/openjdk/jmh

JMH 會(huì)首先執(zhí)行預(yù)熱過程,確保 JIT對(duì)代碼進(jìn)行優(yōu)化之后再進(jìn)行真正的迭代測(cè)試,最后輸出測(cè)試的結(jié)果。

image-20241012141446910

image-20241012141722857

import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;// 預(yù)熱次數(shù) 時(shí)間
@Warmup(iterations = 5, time = 1)
// 啟動(dòng)多少個(gè)線程
@Fork(value=1, jvmArgsAppend= {"-Xms1g", "-Xmx1g"})
// 指定顯示結(jié)果
@BenchamarkMode(Mode.AverageTime)
// 指定顯示結(jié)果單位
@OutputTimeUnit(TimeUnit.NANOSECONDS)
// 變量共享范圍
@State(Scope.Benchmark)
public class MyBenchmark {@Benchmarkpublic void testMethod() {// place your benchmarked code hereint i = 0;i++;return i;}// 在項(xiàng)目中測(cè)試時(shí),盡量打包成 jar 包public static void main(String[] args) throws RunnerException {Options options = new OptionsBuilder();.include(MyBenchmark.class.getSimpleName()).forks(1).build();new Runner(options).run();}
}
編寫測(cè)試方法,幾個(gè)需要注意的點(diǎn):
  • 死代碼問題

  • 黑洞的用法

  • 通過 maven 的 verify命令,檢測(cè)代碼問題并打包成 jar包。通過 java -jar target/benchmarks.jar 命令執(zhí)行基準(zhǔn)測(cè)試。

    測(cè)試結(jié)果通過 https://imh.morethan.io/ 生成可視化的結(jié)果。

案例:日期格式化方法性能測(cè)試

image-20241012143940299

總結(jié):日期格式化方法性能測(cè)試

image-20241012143835919

案例實(shí)戰(zhàn)

image-20241012151014091

image-20241012154017957

image-20241012154144670

http://www.risenshineclean.com/news/2794.html

相關(guān)文章:

  • 小程序推廣任務(wù)入口徐州seo企業(yè)
  • 建自己的網(wǎng)站用多少錢關(guān)鍵詞如何快速排名
  • 貴陽(yáng)公司網(wǎng)頁(yè)網(wǎng)站建設(shè)seo工資
  • 網(wǎng)站資質(zhì)優(yōu)化百度空間登錄入口
  • b2b電子商務(wù)網(wǎng)站建設(shè)seo資料站
  • 漳州軟件開發(fā)公司寧波網(wǎng)站建設(shè)網(wǎng)站排名優(yōu)化
  • 畢業(yè)論文網(wǎng)站建設(shè)報(bào)告seo顧問賺錢嗎
  • 做爰視頻網(wǎng)站在線看合肥關(guān)鍵詞排名
  • 包頭人臉檢測(cè)系統(tǒng)廣州seo優(yōu)化排名公司
  • 動(dòng)易網(wǎng)站后臺(tái)域名在線查詢
  • wordpress掛下載鏈接正規(guī)seo排名外包
  • 廣東省建設(shè)安全監(jiān)督站的網(wǎng)站識(shí)圖
  • 關(guān)于政府網(wǎng)站集約化建設(shè)的報(bào)告鎮(zhèn)江seo優(yōu)化
  • 界面做的比較好的網(wǎng)站推廣普通話宣傳語(yǔ)手抄報(bào)
  • 網(wǎng)站建設(shè)工資高嗎成都企業(yè)網(wǎng)站seo技術(shù)
  • 企業(yè)網(wǎng)站模板網(wǎng)頁(yè)模板百度網(wǎng)盤怎么用
  • 怎么用vs2010做網(wǎng)站以網(wǎng)紅引流促業(yè)態(tài)提升
  • 寧夏住房和城鄉(xiāng)建設(shè)廳門戶網(wǎng)站滄州seo公司
  • 管理培訓(xùn)機(jī)構(gòu)企業(yè)專業(yè)搜索引擎優(yōu)化
  • 濰坊做網(wǎng)站聯(lián)系方式seo的方法
  • wordpress get attachment泉州百度推廣排名優(yōu)化
  • 做爰視頻網(wǎng)站在線看拼多多女裝關(guān)鍵詞排名
  • 專門做創(chuàng)意桌椅的網(wǎng)站網(wǎng)站建設(shè)黃頁(yè)視頻
  • 一個(gè)用vue做的網(wǎng)站軟文范例大全500
  • 手機(jī)怎么創(chuàng)建自己的網(wǎng)頁(yè)seo優(yōu)化首頁(yè)
  • web個(gè)人網(wǎng)站設(shè)計(jì)方案互聯(lián)網(wǎng)
  • 做網(wǎng)站的系統(tǒng)設(shè)計(jì)網(wǎng)絡(luò)營(yíng)銷團(tuán)隊(duì)
  • 免費(fèi)推廣網(wǎng)站怎么做小學(xué)生一分鐘新聞播報(bào)
  • 營(yíng)銷型網(wǎng)站建設(shè)便宜數(shù)字營(yíng)銷公司排行榜
  • 關(guān)于做網(wǎng)站的策劃書電商平臺(tái)排行榜