1. 程式人生 > >JAVA程序佔用高記憶體原因分析與優化方法

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