JAVA程序佔用高記憶體原因分析與優化方法
首先看一下一個java程序的jmap輸出:
程式碼如下:
[[email protected] ~]$ jmap -heap 837
Attaching to process ID 837, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.10-b01
using thread-local object allocation.
Parallel GC with 2 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 4294967296 (4096.0MB)
NewSize = 1310720 (1.25MB)
MaxNewSize = 17592186044415 MB
OldSize = 5439488 (5.1875MB)
NewRatio = 2
SurvivorRatio = 8
PermSize = 21757952 (20.75MB)
MaxPermSize = 85983232 (82.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 41025536 (39.125MB)
used = 18413552 (17.560531616210938MB)
free = 22611984 (21.564468383789062MB)
44.883147900858624% used
From Space:
capacity = 4325376 (4.125MB)
used = 3702784 (3.53125MB)
free = 622592 (0.59375MB)
85.60606060606061% used
To Space:
capacity = 4521984 (4.3125MB)
used = 0 (0.0MB)
free = 4521984 (4.3125MB)
0.0% used
PS Old Generation
capacity = 539820032 (514.8125MB)
used = 108786168 (103.74657440185547MB)
free = 431033864 (411.06592559814453MB)
20.152302906758376% used
PS Perm Generation
capacity = 85983232 (82.0MB)
used = 60770232 (57.95500946044922MB)
free = 25213000 (24.04499053955078MB)
70.67684080542588% used
然後再用ps看看:
程式碼如下:
[[email protected] ~]$ ps -p 837 -o vsz,rss
VSZ RSS
7794992 3047320
關於這裡的幾個generation網上資料一大把就不細說了,這裡算一下求和可以得知前者總共給Java環境分配了644M的記憶體,而ps輸出的VSZ和RSS分別是7.4G和2.9G,這到底是怎麼回事呢?
前面jmap輸出的內容裡,MaxHeapSize 是在命令列上配的,-Xmx4096m,這個java程式可以用到的最大堆記憶體。
VSZ是指已分配的線性空間大小,這個大小通常並不等於程式實際用到的記憶體大小,產生這個的可能性很多,比如記憶體對映,共享的動態庫,或者向系統申請了更多的堆,都會擴充套件線性空間大小,要檢視一個程序有哪些記憶體對映,可以使用 pmap 命令來檢視:
程式碼如下:
[[email protected] ~]$ pmap -x 837
837: java
Address Kbytes RSS Dirty Mode Mapping
0000000040000000 36 4 0 r-x-- java
0000000040108000 8 8 8 rwx-- java
00000000418c9000 13676 13676 13676 rwx-- [ anon ]
00000006fae00000 83968 83968 83968 rwx-- [ anon ]
0000000700000000 527168 451636 451636 rwx-- [ anon ]
00000007202d0000 127040 0 0 ----- [ anon ]
...
...
00007f55ee124000 4 4 0 r-xs- az.png
00007fff017ff000 4 4 0 r-x-- [ anon ]
ffffffffff600000 4 0 0 r-x-- [ anon ]
---------------- ------ ------ ------
total kB 7796020 3037264 3023928
這裡可以看到很多anon,這些表示這塊記憶體是由mmap分配的。
RSZ是Resident Set Size,常駐記憶體大小,即程序實際佔用的實體記憶體大小, 在現在這個例子當中,RSZ和實際堆記憶體佔用差了2.3G,這2.3G的記憶體組成分別為:
JVM本身需要的記憶體,包括其載入的第三方庫以及這些庫分配的記憶體
NIO的DirectBuffer是分配的native memory
記憶體對映檔案,包括JVM載入的一些JAR和第三方庫,以及程式內部用到的。上面 pmap 輸出的內容裡,有一些靜態檔案所佔用的大小不在Java的heap裡,因此作為一個Web伺服器,趕緊把靜態檔案從這個Web伺服器中人移開吧,放到nginx或者CDN裡去吧。
JIT, JVM會將Class編譯成native程式碼,這些記憶體也不會少,如果使用了Spring的AOP,CGLIB會生成更多的類,JIT的記憶體開銷也會隨之變大,而且Class本身JVM的GC會將其放到Perm Generation裡去,很難被回收掉,面對這種情況,應該讓JVM使用ConcurrentMarkSweep GC,並啟用這個GC的相關引數允許將不使用的class從Perm Generation中移除, 引數配置: -XX:+UseConcMarkSweepGC -X:+CMSPermGenSweepingEnabled -X:+CMSClassUnloadingEnabled,如果不需要移除而Perm Generation空間不夠,可以加大一點: -X:PermSize=256M -X:MaxPermSize=512M
JNI,一些JNI介面呼叫的native庫也會分配一些記憶體,如果遇到JNI庫的記憶體洩露,可以使用valgrind等記憶體洩露工具來檢測
執行緒棧,每個執行緒都會有自己的棧空間,如果執行緒一多,這個的開銷就很明顯了
jmap/jstack 取樣,頻繁的取樣也會增加記憶體佔用,如果你有伺服器健康監控,記得這個頻率別太高,否則健康監控變成致病監控了。
關於JVM的幾個GC堆和GC的情況,可以用jstat來監控,例如監控程序837每隔1000毫秒重新整理一次,輸出20次:
程式碼如下:
[[email protected] ~]$ jstat -gcutil 837 1000 20
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 80.43 24.62 87.44 98.29 7101 119.652 40 19.719 139.371
0.00 80.43 33.14 87.44 98.29 7101 119.652 40 19.719 139.371
幾個欄位分別含義如下:
S0
年輕代中第一個survivor(倖存區)已使用的佔當前容量百分比
S1
年輕代中第二個survivor(倖存區)已使用的佔當前容量百分比
E
年輕代中Eden(伊甸園)已使用的佔當前容量百分比
O
old代已使用的佔當前容量百分比
P
perm代已使用的佔當前容量百分比
YGC
從應用程式啟動到取樣時年輕代中gc次數
YGCT
從應用程式啟動到取樣時年輕代中gc所用時間(s)
FGC
從應用程式啟動到取樣時old代(全gc)gc次數
FGCT
從應用程式啟動到取樣時old代(全gc)gc所用時間(s)
GCT
從應用程式啟動到取樣時gc用的總時間(s)
結論
因此如果正常情況下jmap輸出的記憶體佔用遠小於 RSZ,可以不用太擔心,除非發生一些嚴重錯誤,比如PermGen空間滿了導致OutOfMemoryError發生,或者RSZ太高導致引起系統公憤被OOM Killer給幹掉,就得注意了,該加記憶體加記憶體,沒錢買記憶體加交換空間,或者按上面列的組成部分逐一排除。
這幾個記憶體指標之間的關係是:VSZ >> RSZ >> Java程式實際使用的堆大小
相關推薦
JAVA程序佔用高記憶體原因分析與優化方法
首先看一下一個java程序的jmap輸出: 程式碼如下: [[email protected] ~]$ jmap -heap 837 Attaching to process ID 837, please wait... Debugger attached suc
Linux伺服器java程序佔用系統記憶體高
使用top命令檢視系統資源的使用情況,命令:top 如圖可以看到java的程序記憶體使用率較高,java程序的記憶體使用率達到了70%+ 2.定位執行緒問題(通過命令檢視9718程序的執行緒情況),命令:ps p 9718 -L -o pcpu,pmem,pid,tid,time
Active session量持續走高即將故障原因分析與優化建議
SID TY ID1 ID2 LMODE REQUEST ---------- -- ---------- ---------- ---------- ---------- 2887 TX 2490401 43458
Handler記憶體洩漏分析與解決方法
最近整理完Android中訊息機制的知識後,想到Handler記憶體洩漏相關的問題也可以順便整理一下,便有了這篇文章,也方便以後自己查閱 為什麼Handler會造成記憶體洩漏 下面是一段簡單的Handler使用 public class MainActivity extend
linux排查java程序佔用CPU過高原因方法
前言 在運維tomcat伺服器時,我們通常會發現cpu的負載過高,大多數原因是由於java程式碼的bug引起的。可能你的java程式碼有很多,檔案也有很多,一行一行的排查是很費時間的。這時我們就可以使用jstack、top等工具對引起問題的程式碼進行定位,
使用tomcat java程序佔用cpu偏高的原因
使用tomcat做為java容器,cpu佔用偏高的原因,目前公司伺服器上面跑的ubuntu環境nginx+tomcat+mysql執行一段時間之後java程序cpu偏高,會出現網站打不開的情況。所以進行了如下分析。 一,首先檢視tomcat日誌,如果有出現OOM錯誤(
Java記憶體溢位的原因有哪些?Java程序佔用記憶體構成有哪些?
JVM記憶體佔用=作業系統自身耗記憶體 + 堆 + Java永久代/元資料區/方法區/常量池/程式碼快取 + 程式計數器(可忽略不計)*執行緒數 + 虛擬機器程序本身 + 虛擬機器棧(執行緒棧)*執行緒數 + 本地方法棧(JNI呼叫)*執行緒數 + 直接記憶體(Java NIO) metaspace的組成 K
linux下查詢java程序佔用CPU過高原因
1. 查詢程序 top檢視程序佔用資源情況 明顯看出java的兩個程序22714,12406佔用過高cpu. 2.查詢執行緒 使用top -H -p <pid>檢視執行緒佔用情況
Java 程序佔用記憶體過多,幕後元凶原來是執行緒太多
那天中午吃飯,一個同事說,那個專案組的人快氣死我了,程式有問題,早晨在群裡@了他們,到中午才回訊息,然後竟然還說他們的程式沒有問題,是我們這邊呼叫的太頻繁了。 簡直想笑。 背景說明 我們當前這個系統和很多的第三方系統做了整合,出問題的就是其中一個三方系統。其實很簡單,他們的系統會產生一些個人待辦任務,然後
公司網絡很慢很卡的原因分析與處理
網絡問題分析與解決方案一、電腦網速突然變的很慢、很卡,怎麽辦1. 如果你是用的無線路由器,不管你有沒有設置無線密碼,都有可能被別人盜用你的網絡,可以關掉無線功能,自已用有線連接上網 2. 如果還不行,那麽啟路由器,有貓的話也要重啟,再試試 3. 如果你的路由器用的時間超過一年,質量不好的話可能內部的部件已經老
ASP.NET MVC 排球計分程序 (三)需求分析與數據庫設計
arch 情況 img 需求 全場 ima 功能 每次 str 需求分析: 軟件名稱:排球計分程序 1、 需要鍵入比賽人員的的姓名,需要根據場上的比賽結果及時做出操作,記分員可以在記錯的情況下撤銷上一部操作。比賽結束,記分員應能查詢到每個隊伍的進球情況,以及攔網、擊球等的
201671010122 2016-2017-2《java程序設計》走進對象與類
pytho 集合 自定義 必須掌握 開始 port 切割 vao 編寫 走進對象與類 上星期同學自主去自習室學習第四章《對象與類》後,回到宿舍,調侃說她在第四章找到對象了,我有點懵,怎麽會呢?在java課
201671010128 2017-09-10 《Java程序設計》之對象與類
構造 進度條 ide 哪些 設計 del 特性 面向對象 般的 向對象程序設計的幾個主要概念:抽象數據類型、類和對象、封裝、類層次(子類)、繼承性、多態性。 類是概念模型,定義對象的所有特性和所需的操作,類是對象的原型。 對象是存在的具體實體,具有明確定義的狀態和行為。
cpu使用率低負載高,原因分析
I/O 即使 因此 內容 一個 sql語句 func 我們 加載 原因總結 產生的原因一句話總結就是:等待磁盤I/O完成的進程過多,導致進程隊列長度過大,但是cpu運行的進程卻很少,這樣就體現到負載過大了,cpu使用率低。 下面內容是具體的原理分析:在分析負載為什麽高之前先
JAVA中OOAD(面向物件分析與設計依賴倒置原則)程式碼例項
簡介:什麼是依賴倒置原則? 軟體設計中,多層次之間相互依賴關係需要倒置為抽象類或介面,而不是直接依賴於具體的實現。 具體表現為: 1、上層模組不應該直接依賴下層實現,而應該依賴下層的抽象 2、每一個單獨的層次,抽象不應該依賴於細節,而細節應該依賴於抽象。 現在有一個使用者類UserBea
linux如何查詢程序佔用的記憶體
1. ps aux命令 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND lizhibin 32986 0.0 13.8 916276 534748 ? Ss
[從0到1搭嵌入式工程]計算程序佔用的記憶體大小
指令碼內容: # cat get_process_mem.sh pid=$(ps|grep myprocess|grep -v grep|awk '{print $1}') cat /proc/$pid/status|grep VmRSS|awk
Makefile:14: *** missing separator. Stop. 原因分析與解決
問題描述: 本人在做朱老師一步步點亮LED實驗時,想通過make命令執行windows中寫好的makefile檔案時,發現 問題分析: 遇到這個問題,本人首先檢查了交叉編譯了是否安裝成功,檢視發現安裝成功,然後再查看了linux中交叉編譯鏈環境變數是否安裝正常。經過
java 程序和執行緒的區別與聯絡
程式:一段靜態的程式碼,一組指令的有序集合,它本身沒有任何執行的含義,它只是一個靜態的實體,是應用軟體執行的藍本。 程序:是程式的一次動態執行,它對應著從程式碼載入,執行至執行完畢的一個完整的過程,是一個動態的實體,它有自己的生命 週期。它因
Handler記憶體洩露分析與解決方案
一、記憶體洩露分析 內部類會有一個指向外部類的引用。 垃圾回收機制中約定,當記憶體中的一個物件的引用計數為0時,將會被回收。 Handler 作為 Android 上的非同步訊息處理機制(好吧,我大多用來進行 worker thread 與 UI