轉自 https://www.jianshu.com/p/479a715d461e
分析給大拇指,轉存
ps aux命令執行結果的幾個列的信息的含義
USER 進程所屬用戶
PID 進程ID
%CPU 進程占用CPU百分比
%MEM 進程占用內存百分比
VSZ 虛擬內存占用大小 單位:kb(killobytes)
RSS 實際內存占用大小 單位:kb(killobytes)
TTY 終端類型
STAT 進程狀態
START 進程啟動時刻
TIME 進程運行時長,進程已經消耗的CPU時間
COMMAND 啟動進程的命令的名稱和參數
top 命令 VSZ,RSS,TTY,STAT, VIRT,RES,SHR,DATA的含義
VIRT:virtual memory usage 虛擬內存
1、進程“需要的”虛擬內存大小,包括進程使用的庫、代碼、數據等
2、假如進程申請100m的內存,但實際只使用了10m,那么它會增長100m,而不是實際的使用量
RES:resident memory usage 常駐內存
1、進程當前使用的內存大小,但不包括swap out
2、包含其他進程的共享
3、如果申請100m的內存,實際使用10m,它只增長10m,與VIRT相反
4、關於庫占用內存的情況,它只統計加載的庫文件所占內存大小
SHR:shared memory 共享內存
1、除了自身進程的共享內存,也包括其他進程的共享內存
2、雖然進程只使用了幾個共享庫的函數,但它包含了整個共享庫的大小
3、計算某個進程所占的物理內存大小公式:RES – SHR
4、swap out后,它將會降下來
DATA
1、數據占用的內存。如果top沒有顯示,按f鍵可以顯示出來。
2、真正的該程序要求的數據空間,是真正在運行中要使用的。
top 運行中可以通過 top 的內部命令對進程的顯示方式進行控制。內部命令如下:
s – 改變畫面更新頻率
l – 關閉或開啟第一部分第一行 top 信息的表示
t – 關閉或開啟第一部分第二行 Tasks 和第三行 Cpus 信息的表示
m – 關閉或開啟第一部分第四行 Mem 和 第五行 Swap 信息的表示
N – 以 PID 的大小的順序排列表示進程列表
P – 以 CPU 占用率大小的順序排列進程列表
M – 以內存占用率大小的順序排列進程列表
h – 顯示幫助
n – 設置在進程列表所顯示進程的數量
q – 退出 top
s – 改變畫面更新周期
序號 列名 含義
a PID 進程id
b PPID 父進程id
c RUSER Real user name
d UID 進程所有者的用戶id
e USER 進程所有者的用戶名
f GROUP 進程所有者的組名
g TTY 啟動進程的終端名。不是從終端啟動的進程則顯示為 ?
h PR 優先級
i NI nice值。負值表示高優先級,正值表示低優先級
j P 最后使用的CPU,僅在多CPU環境下有意義
k %CPU 上次更新到現在的CPU時間占用百分比
l TIME 進程使用的CPU時間總計,單位秒
m TIME+ 進程使用的CPU時間總計,單位1/100秒
n %MEM 進程使用的物理內存百分比
o VIRT 進程使用的虛擬內存總量,單位kb。VIRT=SWAP+RES
p SWAP 進程使用的虛擬內存中,被換出的大小,單位kb。
q RES 進程使用的、未被換出的物理內存大小,單位kb。RES=CODE+DATA
r CODE 可執行代碼占用的物理內存大小,單位kb
s DATA 可執行代碼以外的部分(數據段+棧)占用的物理內存大小,單位kb
t SHR 共享內存大小,單位kb
u nFLT 頁面錯誤次數
v nDRT 最后一次寫入到現在,被修改過的頁面數。
w S 進程狀態。(D=不可中斷的睡眠狀態,R=運行,S=睡眠,T=跟蹤/停止,Z=僵屍進程)
x COMMAND 命令名/命令行
y WCHAN 若該進程在睡眠,則顯示睡眠中的系統函數名
z Flags 任務標志,參考 sched.h
默認情況下僅顯示比較重要的 PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME+、COMMAND 列。可以通過下面的快捷鍵來更改顯示內容。
通過 f 鍵可以選擇顯示的內容。按 f 鍵之后會顯示列的列表,按 a-z 即可顯示或隱藏對應的列,最后按回車鍵確定。
按 o 鍵可以改變列的顯示順序。按小寫的 a-z 可以將相應的列向右移動,而大寫的 A-Z 可以將相應的列向左移動。最后按回車鍵確定。
按大寫的 F 或 O 鍵,然后按 a-z 可以將進程按照相應的列進行排序。而大寫的 R 鍵可以將當前的排序倒轉。
jmap命令
jmap -heap 進程ID
Attaching to process ID 17775, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
using thread-local object allocation.
Parallel GC with 2 thread(s) parallel並發垃圾回收器
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 1006632960 (960.0MB) 當前JVM最大堆大小
NewSize = 20971520 (20.0MB)
MaxNewSize = 335544320 (320.0MB)
OldSize = 41943040 (40.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB) 當前元空間大小
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB 元空間最大大小
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 25165824 (24.0MB)
used = 15424152 (14.709617614746094MB)
free = 9741672 (9.290382385253906MB)
61.29007339477539% used
From Space:
capacity = 1572864 (1.5MB)
used = 1013016 (0.9660873413085938MB)
free = 559848 (0.5339126586914062MB)
64.40582275390625% used
To Space:
capacity = 1572864 (1.5MB)
used = 0 (0.0MB)
free = 1572864 (1.5MB)
0.0% used
PS Old Generation
capacity = 84934656 (81.0MB)
used = 62824456 (59.91407012939453MB)
free = 22110200 (21.08592987060547MB)
73.96798781406733% used
ps命令
ps -p 進程ID -o vsz,rss
VSZ RSS
3701784 413924
VSZ是指已分配的線性空間大小,這個大小通常並不等於程序實際用到的內存大小,產生這個的可能性很多,比如內存映射,共享的動態庫,或者向系統申請了更多的堆,都會擴展線性空間大小。
RSZ是Resident Set Size,常駐內存大小,即進程實際占用的物理內存大小
pmap命令
pmap -x 進程ID
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 4 4 0 r-x-- java
0000000000600000 4 4 4 rw--- java
00000000017f8000 2256 2136 2136 rw--- [ anon ]
00000000c4000000 82944 63488 63488 rw--- [ anon ]
00000000c9100000 572416 0 0 ----- [ anon ]
00000000ec000000 27648 27136 27136 rw--- [ anon ]
00000000edb00000 300032 0 0 ----- [ anon ]
......
total kB 3701784 413924 400716
Address: 內存分配地址
Kbytes: 實際分配的內存大小
RSS: 程序實際占用的內存大小
Mapping: 分配該內存的模塊的名稱
anon,這些表示這塊內存是由mmap分配的
JAVA應用內存分析
JAVA進程內存 = JVM進程內存+heap內存+ 永久代內存+ 本地方法棧內存+線程棧內存 +堆外內存 +socket 緩沖區內存+元空間
linux內存和JAVA堆中的關系
RES = JAVA正在存活的內存對象大小 + 未回收的對象大小 + 其它
VIART= JAVA中申請的內存大小,即 -Xmx -Xms + 其它
其它 = 永久代內存+ 本地方法棧內存+線程棧內存 +堆外內存 +socket 緩沖區內存 +JVM進程內存
xxx.png
JVM內存模型(1.7與1.8之間的區別)
xxx.png
算一下求和可以得知前者總共給Java環境分配了128M的內存,而ps輸出的VSZ和RSS分別是3615M和404M。
RSZ和實際堆內存占用差了276M,內存組成分別為:
JVM本身需要的內存,包括其加載的第三方庫以及這些庫分配的內存
NIO的DirectBuffer是分配的native memory
內存映射文件,包括JVM加載的一些JAR和第三方庫,以及程序內部用到的。上面 pmap 輸出的內容里,有一些靜態文件所占用的大小不在Java的heap里
JIT, JVM會將Class編譯成native代碼,這些內存也不會少,如果使用了Spring的AOP,CGLIB會生成更多的類,JIT的內存開銷也會隨之變大
JNI,一些JNI接口調用的native庫也會分配一些內存,如果遇到JNI庫的內存泄露,可以使用valgrind等內存泄露工具來檢測
線程棧,每個線程都會有自己的棧空間,如果線程一多,這個的開銷就很明顯
當前jvm線程數統計:jstack 進程ID |grep ‘tid’|wc –l (linux 64位系統中jvm線程默認棧大小為1MB)
ps huH p 進程ID|wc -l ps -Lf 進程ID | wc -l
top -H -p 進程ID
cat /proc/{pid}/status
jmap/jstack 采樣,頻繁的采樣也會增加內存占用,如果你有服務器健康監控,這個頻率要控制一下
jstat命令
JVM的幾個GC堆和GC的情況,可以用jstat來監控,例如監控某個進程每隔1000毫秒刷新一次,輸出20次
jstat -gcutil 進程ID 1000 20
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 39.58 95.63 74.66 98.35 96.93 815 4.002 3 0.331 4.333
0.00 39.58 95.76 74.66 98.35 96.93 815 4.002 3 0.331 4.333
41.67 0.00 1.62 74.67 98.35 96.93 816 4.006 3 0.331 4.337
41.67 0.00 1.67 74.67 98.35 96.93 816 4.006 3 0.331 4.337
41.67 0.00 3.12 74.67 98.35 96.93 816 4.006 3 0.331 4.337
41.67 0.00 3.12 74.67 98.35 96.93 816 4.006 3 0.331 4.337
41.67 0.00 8.39 74.67 98.35 96.93 816 4.006 3 0.331 4.337
41.67 0.00 9.85 74.67 98.35 96.93 816 4.006 3 0.331 4.337
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及SpringBoot
鏈接:https://www.jianshu.com/p/479a715d461e
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。