JAVA進程占用高內(nèi)存原因分析與優(yōu)化方法
來源:易賢網(wǎng) 閱讀:2350 次 日期:2014-12-02 15:11:27
溫馨提示:易賢網(wǎng)小編為您整理了“JAVA進程占用高內(nèi)存原因分析與優(yōu)化方法”,方便廣大網(wǎng)友查閱!

首先看一下一個java進程的jmap輸出:

代碼如下:

[lex@chou ~]$ 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看看:

代碼如下:

[lex@chou ~]$ ps -p 837 -o vsz,rss

VSZ RSS

7794992 3047320

關于這里的幾個generation網(wǎng)上資料一大把就不細說了,這里算一下求和可以得知前者總共給Java環(huán)境分配了644M的內(nèi)存,而ps輸出的VSZ和RSS分別是7.4G和2.9G,這到底是怎么回事呢?

前面jmap輸出的內(nèi)容里,MaxHeapSize 是在命令行上配的,-Xmx4096m,這個java程序可以用到的最大堆內(nèi)存。

VSZ是指已分配的線性空間大小,這個大小通常并不等于程序?qū)嶋H用到的內(nèi)存大小,產(chǎn)生這個的可能性很多,比如內(nèi)存映射,共享的動態(tài)庫,或者向系統(tǒng)申請了更多的堆,都會擴展線性空間大小,要查看一個進程有哪些內(nèi)存映射,可以使用 pmap 命令來查看:

代碼如下:

[lex@chou ~]$ 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,這些表示這塊內(nèi)存是由mmap分配的。

RSZ是Resident Set Size,常駐內(nèi)存大小,即進程實際占用的物理內(nèi)存大小, 在現(xiàn)在這個例子當中,RSZ和實際堆內(nèi)存占用差了2.3G,這2.3G的內(nèi)存組成分別為:

JVM本身需要的內(nèi)存,包括其加載的第三方庫以及這些庫分配的內(nèi)存

NIO的DirectBuffer是分配的native memory

內(nèi)存映射文件,包括JVM加載的一些JAR和第三方庫,以及程序內(nèi)部用到的。上面 pmap 輸出的內(nèi)容里,有一些靜態(tài)文件所占用的大小不在Java的heap里,因此作為一個Web服務器,趕緊把靜態(tài)文件從這個Web服務器中人移開吧,放到nginx或者CDN里去吧。

JIT, JVM會將Class編譯成native代碼,這些內(nèi)存也不會少,如果使用了Spring的AOP,CGLIB會生成更多的類,JIT的內(nèi)存開銷也會隨之變大,而且Class本身JVM的GC會將其放到Perm Generation里去,很難被回收掉,面對這種情況,應該讓JVM使用ConcurrentMarkSweep GC,并啟用這個GC的相關參數(shù)允許將不使用的class從Perm Generation中移除, 參數(shù)配置: -XX:+UseConcMarkSweepGC -X:+CMSPermGenSweepingEnabled -X:+CMSClassUnloadingEnabled,如果不需要移除而Perm Generation空間不夠,可以加大一點: -X:PermSize=256M -X:MaxPermSize=512M

JNI,一些JNI接口調(diào)用的native庫也會分配一些內(nèi)存,如果遇到JNI庫的內(nèi)存泄露,可以使用valgrind等內(nèi)存泄露工具來檢測

線程棧,每個線程都會有自己的棧空間,如果線程一多,這個的開銷就很明顯了

jmap/jstack 采樣,頻繁的采樣也會增加內(nèi)存占用,如果你有服務器健康監(jiān)控,記得這個頻率別太高,否則健康監(jiān)控變成致病監(jiān)控了。

關于JVM的幾個GC堆和GC的情況,可以用jstat來監(jiān)控,例如監(jiān)控進程837每隔1000毫秒刷新一次,輸出20次:

代碼如下:

[lex@chou ~]$ 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(幸存區(qū))已使用的占當前容量百分比

S1

年輕代中第二個survivor(幸存區(qū))已使用的占當前容量百分比

E

年輕代中Eden(伊甸園)已使用的占當前容量百分比

O

old代已使用的占當前容量百分比

P

perm代已使用的占當前容量百分比

YGC

從應用程序啟動到采樣時年輕代中gc次數(shù)

YGCT

從應用程序啟動到采樣時年輕代中gc所用時間(s)

FGC

從應用程序啟動到采樣時old代(全gc)gc次數(shù)

FGCT

從應用程序啟動到采樣時old代(全gc)gc所用時間(s)

GCT

從應用程序啟動到采樣時gc用的總時間(s)

結論

因此如果正常情況下jmap輸出的內(nèi)存占用遠小于 RSZ,可以不用太擔心,除非發(fā)生一些嚴重錯誤,比如PermGen空間滿了導致OutOfMemoryError發(fā)生,或者RSZ太高導致引起系統(tǒng)公憤被OOM Killer給干掉,就得注意了,該加內(nèi)存加內(nèi)存,沒錢買內(nèi)存加交換空間,或者按上面列的組成部分逐一排除。

這幾個內(nèi)存指標之間的關系是:VSZ >> RSZ >> Java程序?qū)嶋H使用的堆大小

更多信息請查看IT技術專欄

更多信息請查看網(wǎng)絡編程
易賢網(wǎng)手機網(wǎng)站地址:JAVA進程占用高內(nèi)存原因分析與優(yōu)化方法

2026國考·省考課程試聽報名

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權所有:易賢網(wǎng)