[JVM] JVM內存調優

🌸個人主頁:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵?熱門專欄:
🧊 Java基本語法(97平均質量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection與數據結構 (93平均質量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀線程與網絡(97平均質量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql數據庫(95平均質量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均質量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均質量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
🎃Redis(97平均質量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482
🐰RabbitMQ(97平均質量分) https://blog.csdn.net/2301_80050796/category_12792900.html?spm=1001.2014.3001.5482
感謝點贊與關注~~~

在這里插入圖片描述

目錄

  • 1. 內存溢出和內存泄漏
    • 1.1 基本概念
    • 1.2 內存泄漏的常見場景
    • 1.3 常見的虛擬機參數
  • 2. 解決內存溢出的辦法
    • 2.1 常用的監控工具
      • 2.1.1 Top命令:
      • 2.2.2 VisualVM
      • 2.2.3 Arthas
      • 2.2.4 使用阿里arthas tunnel管理所有的需要監控的程序
      • 2.2.5 Prometheus+Grafana
    • 2.2 堆內存情況的對比
    • 2.3 產生內存溢出的原因一: 代碼中的內存泄漏
      • 2.3.1 equals和hashCode導致的內存泄漏
      • 2.3.2 內部類引用外部類
      • 2.3.3 ThreadLocal的使用
      • 2.3.4 String的intern方法
      • 2.3.5 通過靜態字段保存對象
      • 2.3.6 資源沒有正常關閉
    • 2.4 產生內存溢出的原因二: 并發請求問題
    • 2.5 診斷
      • 2.5.1 內存快照
      • 2.5.2 MAT內存泄漏檢測原理
      • 2.5.3 服務器上的內存快照導出和分析
        • 背景:
        • 思路:

1. 內存溢出和內存泄漏

1.1 基本概念

內存泄漏: 在java中如果不再使用一個對象,但是該對象依然在GC Root的引用鏈上,這個對象就不會被垃圾回收器回收,這種情況就稱之為內存泄漏.
內存泄漏絕大多數都是由對內存泄漏引起的,所以后續沒有特別說明則討論的都是堆內存泄漏.
比如圖中,如果學生對象1不再使用
在這里插入圖片描述
可以選擇將ArrayList到學生對象1的引用刪除:
在這里插入圖片描述
或者將對象A堆ArrayList的引用刪除,這樣所有的學生包括ArrayList都可以回收:
在這里插入圖片描述
但是如果不移除這兩個引用中的任何一個,學生對象1就屬于內存泄漏了.
少量的內存泄漏可以容忍,但是如果發生持續的內存泄漏,就像滾雪球一樣越滾越大,不管由多大的內存遲早會被消耗完,最終導致內存溢出,但是產生的內存溢出并不只有內存泄漏這一種原因.
在這里插入圖片描述
這些學生對象如果都不再使用,越積越多,就會導致超過堆內存的上限出現內存溢出.
正常情況的內存結構圖如下:
在這里插入圖片描述
內存溢出出現時如下:
在這里插入圖片描述
內存泄漏的對象依然在GC Root引用鏈上需要使用的對象加起來沾滿了內存空間,無法為新的對象分配內存.

1.2 內存泄漏的常見場景

  1. 內存泄漏導致溢出的常見場景是大型的java后端應用中,在處理用戶的請求之后,沒有及時將用戶的數據刪除,隨著用戶請求數量越來越多,內存泄漏的對象占滿了對內存最終導致內存溢出.
    這種產生的內存溢出會直接導致用戶請求無法處理,影響用戶的正常使用.重啟可以恢復應用使用,但是在運行一段時間之后依然會出現內存溢出.

在這里插入圖片描述
代碼:

package com.itheima.jvmoptimize.controller;import com.itheima.jvmoptimize.entity.UserEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@RestController
@RequestMapping("/leak2")
public class LeakController2 {private static Map<Long,Object> userCache = new HashMap<>();/*** 登錄接口 放入hashmap中*/@PostMapping("/login")public void login(String name,Long id){userCache.put(id,new byte[1024 * 1024 * 300]);}/*** 登出接口,刪除緩存的用戶信息*/@GetMapping("/logout")public void logout(Long id){userCache.remove(id);}}

設置虛擬機參數,將最大堆內存設置為1g:
在這里插入圖片描述
PostMan連續調用login傳遞不同的id,但是不調用logout.
在這里插入圖片描述
調用幾次之后就會出現內存溢出:在這里插入圖片描述
2. 第二種常見的是分布式任務調度系統如Elastic-job、Quartz等進行任務調度時,被調度的java應用在調度任務結束中出現了內存泄漏,最終導致多次調度之后內存溢出.
這種產生的內存溢出會導致應用執行下次的調度任務執行,同樣重啟可以恢復應用使用,但是在調度執行一段時間之后依然會出現內存溢出.
在這里插入圖片描述
開啟定時任務:
在這里插入圖片描述定時任務代碼:

package com.itheima.jvmoptimize.task;import com.itheima.jvmoptimize.leakdemo.demo4.Outer;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;@Component
public class LeakTask {private int count = 0;private List<Object> list = new ArrayList<>();@Scheduled(fixedRate = 100L)public void test(){System.out.println("定時任務調用" + ++count);list.add(new Outer().newList());}
}

啟動程序之后很快就出現了內存溢出:
在這里插入圖片描述

1.3 常見的虛擬機參數

在這里插入圖片描述

2. 解決內存溢出的辦法

在這里插入圖片描述
首先要熟悉一些常用的監控工具:

2.1 常用的監控工具

2.1.1 Top命令:

top命令是Linux下用來查看系統信息的一個命令,它提供我們去實地地去查看系統的資源,比如執行時的進程,線程和系統參數等信息,進程使用的內存為res(常駐內存)-shr(共享內存)
在這里插入圖片描述

優點:

  • 操作簡單
  • 無額外的軟件安裝

缺點:

  • 只能查看最基礎的進程信息,無法查看到每個部分的內存占用(堆,方法區,堆外).

2.2.2 VisualVM

==VisualVM是多功能合一的java故障排除工具并且他是一款可視化工具,==整合了命令行JDK工具和輕量級分析功能,功能非常強大.這款軟件在Oracle JDK 6~8 中發布,但是在 Oracle JDK 9 之后不在JDK安裝目錄下需要單獨下載.下載地址:
https://visualvm.github.io/

優點:

  • 功能豐富,實時監控CPU,內存,線程等詳細信息.
  • 支持idea插件,開發過程中也可以使用.

缺點:

  • 對大量集群化部署的java進程需要手動進行管理.

如果需要進行遠程監控,可以通過jmx方式進行連接,在啟動java程序時為配置文件添加如下參數:

-Djava.rmi.server.hostname=服務器ip地址
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9122
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

右鍵點擊remote:

在這里插入圖片描述
填寫服務器的IP地址:

在這里插入圖片描述
右鍵點擊JMX連接:
在這里插入圖片描述
填寫IP地址和端口號,勾選不需要SSL安全驗證:
在這里插入圖片描述
雙擊成功連接:

在這里插入圖片描述

2.2.3 Arthas

Arthas是一款線上監控診斷產品,通過全局視角實時查看應用Load,內存,gc,線程的狀態信息,并能在不修改引用代碼的情況下,對業務問題進行診斷,包括查看方法調用的出入參,異常,檢測方法執行耗時,類加載信息等,大大提升線上問題的排查效率.

在這里插入圖片描述
優點:

  • 功能強大,不止于監控基礎信息,還可以監控單個方法的執行耗時等細節內容.
  • 支持應用的集群管理

缺點:
部分高級功能使用門檻較高

2.2.4 使用阿里arthas tunnel管理所有的需要監控的程序

背景:
小李的團隊已經普及了arthas的使用,但是由于使用了微服務框架,生產環境上的應用數量非常多,使用arthas還得登錄到每一臺服務器上再去操作非常不方便,他看到官方文檔上可以使用tunnel來管理所有需要監控的程序.
在這里插入圖片描述
步驟:

  1. 在SpringBoot程序中添加了Arthas的依賴(支持SpringBoot2),在配置文件中添加了tunnel服務端的地址,便于tunnel去監控所有的程序.
  2. 將tunnel服務端程序部署在某臺服務器上并啟動.
  3. 啟動java程序
  4. 打開tunnel的服務端頁面,查看所有的進程列表,并選擇進程進行arthas的操作.

pom.xml添加依賴:

<dependency><groupId>com.taobao.arthas</groupId><artifactId>arthas-spring-boot-starter</artifactId><version>3.7.1</version>
</dependency>

application.yml中添加配置:

arthas:#tunnel地址,目前是部署在同一臺服務器,正式環境需要拆分tunnel-server: ws://localhost:7777/ws#tunnel顯示的應用名稱,直接使用應用名app-name: ${spring.application.name}#arthas http訪問的端口和遠程連接的端口http-port: 8888telnet-port: 9999

我們需要提前準備好arthas-tunnel-server.3.7.1-fatjar.jar上傳到服務器,并使用nohup java -jar -Darthas.enable-detail-pages=true arthas-tunnel-server.3.7.1-fatjar.jar &命令啟動該程序. -Darthas.enable-detail-pages=true參數作用是可以有一個頁面展示內容.通過服務器ip地址:8080/apps.html打開頁面,目前沒有注冊上來任何應用.
在這里插入圖片描述
啟動SpringBoot應用,如果在一臺服務器上,注意區分端口.

-Dserver.port=tomcat端口號
-Darthas.http-port=arthas的http端口號
-Darthas.telnet-port=arthas的telnet端口號端口號

在這里插入圖片描述
最終就能看到兩個應用:
在這里插入圖片描述
單擊應用就可以進入操作arthas了.

2.2.5 Prometheus+Grafana

Prometheus+Grafana是企業中運維常用的監控方案,其中Prometheus用來采集系統或者應用的相關數據,同時具備告警功能,Grafana可以將Prometheus采集到的數據以可視化的方式進行展示.
在這里插入圖片描述
優點:

  • 支持系統級別和應用級別的監控,比如Linux操作系統,Redi,MySQL,java進程.
  • 支持告警運行定義告警指標,通過郵件,短信等方式盡早通知相關人員進行處理.

缺點:
環境搭建較為復雜,一般有運維人員完成

2.2 堆內存情況的對比

  • 正常情況
    • 處理業務時會出現上下起伏,業務對象頻繁創建內存會升高,觸發MinorGC之后會降下來.
    • 手動執行FULLGC之后,內存大小會驟降,而且每次降完之后的大小是接近的.
    • 長時間觀察內存曲線應該是在一個范圍內.
      在這里插入圖片描述
    • 出現內存泄漏
      • 處于持續增長的情況,即使MinorGC也不能把大部分對象回收
      • 手動FullGC之后的內存量每一次都在增長
      • 長時間觀察內存曲線持續增長

2.3 產生內存溢出的原因一: 代碼中的內存泄漏

總結了6種產生的內存泄漏的原因,均來自java代碼的處理不當:

  • equals()和hashCode(),不正確的equals()和hashCode()實現導致內存泄漏
  • ThreadLocal的使用,由于線程池中的線程不被回收導致的ThreadLocal內存泄漏
  • 內部類引用外部類,非靜態的內部類和匿名內部類的錯誤使用導致內存泄漏.
  • String的Intern方法,由于JDK6中的字符串常量池位于永久代,intern被大量的調用并保存產生的內存泄漏
  • 通過靜態字段保存的對象,大量的數據在靜態變量中被引用,但是不再使用,成為了內存泄漏.
  • 資源沒有正常關閉,由于資源沒有調用close方法正常關閉,導致的內存溢出.

2.3.1 equals和hashCode導致的內存泄漏

問題:
在定義新類時沒有重寫正確的equals()和hashCode()方法,在使用HashMap的場景下,如果使用這個類對象作為key,HashMap在判斷key是否已經存在時會使用這些方法,如果重寫方式不正確,會導致相同的數據被保存多份.
正常情況:

  1. 以JDK8為例,首先調用hash方法計算key的哈希值,hash方法中會使用到key的hashCode方法,根據hash方法的結果決定存放的數組中的位置.
  2. 如果沒有元素,直接放入,如果有元素,先判斷key是否相等,會用到equals方法,如果key相等,直接替換value,key不相等,走鏈表或者是紅黑樹查找邏輯,其中也會使用equals對比是否相等.
    在這里插入圖片描述
    異常情況:
  3. hashCode方法實現不正確,會導致相同id的學生對象計算出來的hash值不同,可能會被分到不同的槽中.
    在這里插入圖片描述
  4. equals方法實現不正確,會導致key在對比時,即便學生對象的id是相同的,也被認為是不同的key.
    在這里插入圖片描述5. 長時間運行之后HashMap中會保存大量相同的id的學生的數據.

在這里插入圖片描述
比如下面的代碼,就會發生內存泄漏,我們在student中不重寫hashCode和equals方法,我們直接

public class Student {private String name;private Integer id;private byte[] bytes = new byte[1024 * 1024];public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}
}
package com.itheima.jvmoptimize.leakdemo.demo2;import java.util.HashMap;
import java.util.Map;public class Demo2 {public static long count = 0;public static Map<Student,Long> map = new HashMap<>();public static void main(String[] args) throws InterruptedException {while (true){if(count++ % 100 == 0){Thread.sleep(10);}Student student = new Student();student.setId(1);student.setName("張三");map.put(student,1L);}}
}

運行之后觀察VisualVM,出現了內存泄漏的現象.
在這里插入圖片描述
解決方案:

  1. 在定義實體時,始終重寫equals()和hashCode()方法.
  2. 重寫時一定要確定使用了唯一標識去區分不同的對象,比如用戶的id等.
  3. HashMap使用時盡量使用使用編號id等數據作為key,不要將整個實體類對象作為key存放.

2.3.2 內部類引用外部類

問題:

  1. 非靜態的內部類默認會持有外部類,盡管代碼上不在使用外部類,所以如果有地方引用了這個非靜態內部類,會導致外部類也被引用,垃圾回收時無法回收這個外部類.
  2. 匿名內部類對象如果在非靜態方法中被創建,會持有調用者對象,垃圾回收時無法回收調用者.
package com.itheima.jvmoptimize.leakdemo.demo3;import java.io.IOException;
import java.util.ArrayList;public class Outer{private byte[] bytes = new byte[1024 * 1024]; //外部類持有數據private static String name  = "測試";class Inner{private String name;public Inner() {this.name = Outer.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());}}
}
package com.itheima.jvmoptimize.leakdemo.demo4;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;public class Outer {private byte[] bytes = new byte[1024 * 1024 * 10];public List<String> newList() {List<String> list = new ArrayList<String>() {{add("1");add("2");}};return list;}public static void main(String[] args) throws IOException {System.in.read();int count = 0;ArrayList<Object> objects = new ArrayList<>();while (true){System.out.println(++count);objects.add(new Outer().newList());}}
}

解決方案:

  1. 這個案例中,使用內部類的原因是可以直接獲取到外部類中的成員變量值,簡化開發,如果不想持有外部類的對象,應該使用靜態內部類.
  2. 使用靜態方法,可以避免匿名內部類持有調用者對象.

2.3.3 ThreadLocal的使用

問題:
如果僅僅使用手動創建線程,就算沒有調用ThreadLocal的remove方法清理數據,也不會產生內存泄漏,因為當線程被回收時,ThreadLocal也同樣被回收,但是如果使用線程池就不一定了.

package com.itheima.jvmoptimize.leakdemo.demo5;import java.util.concurrent.*;public class Demo5 {public static ThreadLocal<Object> threadLocal = new ThreadLocal<>();public static void main(String[] args) throws InterruptedException {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(Integer.MAX_VALUE, Integer.MAX_VALUE,0, TimeUnit.DAYS, new SynchronousQueue<>());int count = 0;while (true) {System.out.println(++count);threadPoolExecutor.execute(() -> {threadLocal.set(new byte[1024 * 1024]);});Thread.sleep(10);}}
}

解決方案: 線程方法執行完,一定要使用ThreadLocal中的remove方法清理對象.

package com.itheima.jvmoptimize.leakdemo.demo5;import java.util.concurrent.*;public class Demo5 {public static ThreadLocal<Object> threadLocal = new ThreadLocal<>();public static void main(String[] args) throws InterruptedException {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(Integer.MAX_VALUE, Integer.MAX_VALUE,0, TimeUnit.DAYS, new SynchronousQueue<>());int count = 0;while (true) {System.out.println(++count);threadPoolExecutor.execute(() -> {threadLocal.set(new byte[1024 * 1024]);threadLocal.remove();});Thread.sleep(10);}}
}

2.3.4 String的intern方法

問題:
JDK6中字符串常量池位于堆內存中的perm gen永久代中==,如果不同字符串的intern方法被大量調用(表示將該字符串加入常量池中),字符串常量池會不停的變大超過永久代內存上限之后就會產生內存溢出問題==.

package com.itheima.jvmoptimize.leakdemo.demo6;import org.apache.commons.lang3.RandomStringUtils;import java.util.ArrayList;
import java.util.List;public class Demo6 {public static void main(String[] args) {while (true){List<String> list = new ArrayList<String>();int i = 0;while (true) {//String.valueOf(i++).intern(); //JDK1.6 perm gen 不會溢出list.add(String.valueOf(i++).intern()); //溢出}}}
}

2.3.5 通過靜態字段保存對象

問題:
如果大量的數據在靜態變量中被長期引用,而靜態字段的生命周期與類本身不同相同,數據就不會被釋放,如果這些數據不再使用,就會成為內存泄漏.

public class Cache {private static Map<String, Object> cache = new HashMap<>();public static void addToCache(String key, Object value) {cache.put(key, value);}public static Object getFromCache(String key) {return cache.get(key);}
}

解決方案:

  1. 盡量減少將對象長時間保存在靜態變量中,如果不再使用,必須將對象刪除(比如在集合中)或者將靜態變量攝者為null.
  2. 使用單例模式時,盡量使用懶加載,而不是立即加載.
package com.itheima.jvmoptimize.leakdemo.demo7;import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;@Lazy //懶加載
@Component
public class TestLazy {private byte[] bytes = new byte[1024 * 1024 * 1024];
}
  1. Spring的Bean中不要長期存放大量對象,如果是緩存用于提升性能,盡量設置過期時間定期失效.
package com.itheima.jvmoptimize.leakdemo.demo7;import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;import java.time.Duration;public class CaffineDemo {public static void main(String[] args) throws InterruptedException {Cache<Object, Object> build = Caffeine.newBuilder()//設置100ms之后就過期.expireAfterWrite(Duration.ofMillis(100)).build();int count = 0;while (true){build.put(count++,new byte[1024 * 1024 * 10]);Thread.sleep(100L);}}
}

2.3.6 資源沒有正常關閉

問題:
連接和流這些資源會占用內存,如果使用完之后沒有關閉,這部分內存不一定會出現內存泄漏,但是會導致close方法不被執行.
解決方案:

  1. 為了防止出現這類的資源對象泄漏問題,必須在finally塊中關閉不再使用的資源.
  2. 從java7開始,使用try-with-resource語法可以用戶自動關閉資源.
    在這里插入圖片描述

2.4 產生內存溢出的原因二: 并發請求問題

通過發送請求向java應用中獲取數據,正常情況下java應用將數據返回之后,這部分數據就可以在內存中被釋放掉.
接收到請求是創建對象:
在這里插入圖片描述
響應返回之后,對象就可以被回收掉:

在這里插入圖片描述
并發請求問題指的是由于用戶的并發請求量可能很大,同時處理數據的時間很長,導致大量的數據存在于內存中,最終超過了內存的上限,導致內存溢出,這類問題的處理思路和內存泄漏類似,首先要定位到對象產生的根源.
在這里插入圖片描述
接下來我們就來模擬一下這種情況:
接口代碼如下:

/*** 大量數據 + 處理慢*/
@GetMapping("/test")
public void test1() throws InterruptedException {byte[] bytes = new byte[1024 * 1024 * 100];//100mThread.sleep(10 * 1000L);
}
  1. 接下來我們使用Jmeter進行并發測試,把線程參數設置為100.
    在這里插入圖片描述
  2. 添加虛擬機參數
    在這里插入圖片描述
  3. 點擊運行進行壓測,很快就出現了內存溢出:
    在這里插入圖片描述
    比如我們再來看一個案例:
  4. 代碼如下:
/*** 登錄接口 傳遞名字和id,放入hashmap中*/
@PostMapping("/login")
public void login(String name,Long id){userCache.put(id,new UserEntity(id,name));
}
  1. 在壓測工具中添加name字段,id字段設置為指定區間的隨機數
    在這里插入圖片描述
  2. 點擊測試,一段時間之后同樣出現了內存溢出:
    在這里插入圖片描述

2.5 診斷

2.5.1 內存快照

當堆內存溢出時,需要在堆內存溢出時將整個堆內存保存下來,生成快照文件.
使用MAT打開hprof文件,并選擇內存泄漏檢測功能,MAT會自動根據內存快照中保存的數據分析內存泄漏的根源.
在這里插入圖片描述
生成內存快照的java虛擬機參數:
-XX:+HeapDumpOnOutOfMemoryError: 發生OutOfMemoryError錯誤時,自動生成hprof內存快照文件.
-XX:HeapDumpPath=<path>: 指定hprof文件的輸出路徑.
使用MAT打開hprof文件,并選擇內存泄漏檢測功能,MAT會自動根據內存快照中保存的數據分析內存泄漏的根源.
在程序中添加jvm參數:

-Xmx256m -Xms256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\jvm\dump\test1.hprof

運行程序之后:
在這里插入圖片描述
使用MAT打開hprof文件,首頁就顯示了MAT檢測出來的內存泄漏問題的原因.
在這里插入圖片描述
點擊Detail查看詳情,這個線程持有了大量的字節數組:
在這里插入圖片描述

2.5.2 MAT內存泄漏檢測原理

MAT提供了稱為支配樹的對象圖.支配樹展示的是對象實例間支配關系,在對象引用中,所有指向對象的B路徑都經過A,則認為對象A支配對象B.
如下圖,A引用BC,BC引用D,C引用ED,E引用F,轉成支配樹之后,由于E只有C引用,所以E掛在C上,接下來BCDF都由其他至少1個對象引用,所以追溯上去,只有A滿足支配它們的條件.

在這里插入圖片描述
支配樹中對象本身占用的空間稱之為淺堆,支配樹種對象的子樹就是所有被該對象支配的內容,這些內容組成了對象的深堆,也稱之為保留集==,深堆的大小表示該對象如果可以被回收,能釋放多大的內存空間==.
如下圖: C自身包含一個淺堆,而C地下掛了E,所以C+E占用的空間大小代表C的深堆.
在這里插入圖片描述
在MAT中,也有查看MAT支配樹的功能:
在這里插入圖片描述
輸入main進行搜索,可以看到支配樹的整體結構:

在這里插入圖片描述
同時也可以看到字符串的淺堆大小和深堆大小:
在這里插入圖片描述

2.5.3 服務器上的內存快照導出和分析

剛才我們都是在本地導出內存快照的,并且是程序已經出現了內存溢出,接下來我們要做到防患于未然,一點看到大量內存增長就去分析內存快照,此時內存還沒有溢出,怎么樣去獲得內存快照文件呢?

背景:

小李的團隊通過監控系統發現有一個服務的內存在持續增長,希望盡快通過內存快照分析增長的原因,由于并未產生內存溢出所以不能通過HeapDumpOnOutOfMemoryError參數生成內存快照.

思路:

導出運行中系統的內存快照,比較簡單的方式有兩種,注意只需要導出標記為存活的對象:

  • 通過JDK自帶的jmap命令導出,格式為:jmap -dump:live,format=b,file=文件路徑和文件名 進程ID
  • 通過arthas的heapdump命令導出,格式為:heapdump --live文件路徑和文件名.

先使用jps或者ps -ef查看進程ID:
在這里插入圖片描述
通過jmap命令導出內存快照文件,live代表值保存存活對象,format=b用二進制方式保存:
在這里插入圖片描述
也可以在arthas中輸出heapdump命令:

在這里插入圖片描述
接下來下載到本地分析即可.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/83640.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/83640.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/83640.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot 從Socket 到Netty網絡編程(下):Netty基本開發與改進【心跳、粘包與拆包、閑置連接】

上一篇&#xff1a;《Spring Boot 從Socket 到Netty網絡編程&#xff08;上&#xff09;&#xff1a;SOCKET 基本開發&#xff08;BIO&#xff09;與改進(NIO)》 前言 前文中我們簡單介紹了基于Socket的BIO&#xff08;阻塞式&#xff09;與NIO&#xff08;非阻塞式&#xff0…

python編寫賽博朋克風格天氣查詢程序

工具介紹 這個天氣查詢工具是一個基于 Python 的桌面應用程序,使用了tkinter庫來創建圖形用戶界面(GUI),并通過requests庫調用 Open - Meteo API 獲取天氣數據。它具有賽博朋克風格的界面設計,提供了當前天氣信息、15 天天氣預報以及詳細的天氣數據展示,同時還包含溫度趨…

從二叉樹到 STL:揭開 set 容器的本質與用法

前言&#xff1a; 上次介紹完二叉搜索樹后&#xff0c;更新中斷了一段時間&#xff0c;先向大家致歉。最近學習狀態有些起伏&#xff0c;但我正在努力調整&#xff0c;相信很快會恢復節奏。今天我們繼續深入探討——關聯容器&#xff0c;它在算法和工程中都非常常見和重要。 1…

uv管理spaCy語言模型

本文記錄如何在使用uv管理python項目dependencies時&#xff0c;把spaCy的模型也納入其中. spaCy 一、spaCy簡介 spaCy是一個開源的自然語言處理&#xff08;NLP&#xff09;庫&#xff0c;它主要用于處理文本數據。它支持多種語言&#xff0c;包括英語、中文等。它是由Expl…

python執行測試用例,allure報亂碼且未成功生成報告

allure執行測試用例時顯示亂碼&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;?&#xfffd;&#xfffd;&#xfffd;&#xfffd;?&#xfffd;&#xfffd;&#xfffd;??&#xfffd;&#xfffd;&#xfffd;?&#xfffd;&am…

Rust 學習筆記:Box<T>

Rust 學習筆記&#xff1a;Box Rust 學習筆記&#xff1a;Box<T\>Box\<T> 簡介使用 Box\<T\> 在堆上存儲數據啟用帶有 box 的遞歸類型關于 cons 列表的介紹計算非遞歸類型的大小使用 Box\<T\> 獲取大小已知的遞歸類型 Rust 學習筆記&#xff1a;Box<…

英語寫作中“不少于(小于)”no less than替代no fewer than的用法

no less than 1 liter of water&#xff0c;no fewer than 100 people 是我們的傳統用法。現代英語有一個有趣的現象&#xff0c;就是less 代替fewer 形容可數名詞&#xff0c;例如&#xff1a; Do you have 10 courses each week? No. We have less. 顯然按嚴格語法應該是…

競品分析六大步驟

一、引言 在產品打磨、市場推廣或戰略定位過程中&#xff0c;我們常常會面臨一個關鍵任務——競品分析。一份系統的競品分析不僅能幫助我們知己知彼&#xff0c;優化產品策略&#xff0c;更能成為決策層制定方向的重要依據。競品分析到底該怎么做&#xff1f;今天我將結合自己的…

【Java Web】9.Maven高級

&#x1f4d8;博客主頁&#xff1a;程序員葵安 &#x1faf6;感謝大家點贊&#x1f44d;&#x1f3fb;收藏?評論?&#x1f3fb; 文章目錄 一、分模塊設計與開發 1.1 介紹 1.2 實踐 二、繼承與聚合 2.1 繼承 繼承關系 版本鎖定 2.2 聚合 2.3 繼承與聚合對比 三、…

MySQL 全量、增量備份與恢復

一.MySQL 數據庫備份概述 備份的主要目的是災難恢復&#xff0c;備份還可以測試應用、回滾數據修改、查詢歷史數據、審計等。之前已經學習過如何安裝 MySQL&#xff0c;本小節將從生產運維的角度了解備份恢復的分類與方法。 1 數據備份的重要性 在企業中數據的價值至關…

第六個微信小程序:教師工具集

源于工作需要&#xff0c;下面開始。 安裝及使用 | Taro 文檔 vscode 代碼管理 git 輔助 開發技術如上&#xff1a; 1.開始創建模板 taro4.1.1 $ taro init teachers-tools 2.用vsocde開始吧。 選擇 第二個文件夾找一。 (base) PS D:\react\teachers-tools> pnpm…

Linux 里 su 和 sudo 命令這兩個有什么不一樣?

《小菜狗 Linux 操作系統快速入門筆記》目錄&#xff1a; 《小菜狗 Linux 操作系統快速入門筆記》&#xff08;01.0&#xff09;文章導航目錄【實時更新】 Linux 是一個多用戶的操作系統。在 Linux 中&#xff0c;理論上來說&#xff0c;我們可以創建無數個用戶&#xff0c;但…

Elastic 獲得 AWS 教育 ISV 合作伙伴資質,進一步增強教育解決方案產品組合

作者&#xff1a;來自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通過搜索 AI 和云創新推動教育領域的數字化轉型。 我們非常高興地宣布&#xff0c;Elastic 已獲得 AWS 教育 ISV 合作伙伴資質。這一重要認證表明&#xff0c;Elastic 作為 …

服務器被攻擊了怎么辦

可以上一個高防IP或者AI云防護都是可以的。&#xff08;有效防御CC、APl接口、http、tcp、WEB應用掃描/爬蟲、SYN、WAF、DDOS、UDP、入侵、滲透、SQL注入、XSS跨站腳本攻擊、遠程惡意代碼執行、session fixation、Webshell攻擊、惡意請求&#xff0c;惡意掃描、暴力破解、CSRF等…

【學習筆記】Circuit Tracing: Revealing Computational Graphs in Language Models

Circuit Tracing: Revealing Computational Graphs in Language Models 替代模型(Replacement Model)&#xff1a;用更多的可解釋的特征來替代transformer模型的神經元。 歸因圖(Attribution Graph)&#xff1a;展示特征之間的相互影響&#xff0c;能夠追蹤模型生成輸出時所采用…

靈活控制,modbus tcp轉ethernetip的 多功能水處理方案

油田自動化和先進的油氣行業軟件為油氣公司帶來了諸多益處。其中包括&#xff1a; 1.自動化可以消除多余的步驟、減少人為錯誤并降低運行設備所需的能量&#xff0c;從而降低成本。 2.油天然氣行業不斷追求高水平生產。自動化可以更輕松地減少計劃外停機時間&#xff0c;從而…

是否存在路徑(FIFOBB算法)

題目描述 一個具有 n 個頂點e條邊的無向圖&#xff0c;該圖頂點的編號依次為0到n-1且不存在頂點與自身相連的邊。請使用FIFOBB算法編寫程序&#xff0c;確定是否存在從頂點 source到頂點 destination的路徑。 輸入 第一行兩個整數&#xff0c;分別表示n 和 e 的值&#xff08;1…

windows VeraCrypt – 磁盤加密工具

下載鏈接&#xff1a;夸克網盤分享 VeraCrypt一款跨平臺(Windows/Mac/Linux)的磁盤加密工具&#xff0c;提供多層級數據保護方案&#xff1a;虛擬加密盤&#xff1a;在文件中創建可掛載的加密虛擬磁盤全設備加密&#xff1a;支持分區/USB/硬盤等存儲設備的全盤加密系統盤加密&…

客戶體驗數據使用的三種視角——場景視角

當企業收集到大量的客戶體驗數據之后&#xff0c;應該如何應用&#xff1f;有哪些主要的使用場景和分析視角&#xff1f;體驗家團隊通過三篇文章&#xff0c;陸續介紹三種體驗數據的使用場景&#xff0c;以幫助企業更有效地利用體驗數據進行改進。 01 宏觀層次的“旅程視角” …

時序數據庫IoTDB的UDF Sample算法在數據監控、故障預防的應用

一、數據監控在工業物聯網中的重要性 設備數據監控是工業物聯網&#xff08;IoT&#xff09;中最為廣泛應用的領域之一。通過實時監控工廠機械設備的運行狀態&#xff0c;企業能夠提前發現設備的潛在故障&#xff0c;從而實現預防性維護與可預測性維護。這一做法不僅能有效提升…