cat /proc/[pid]/status
經過/proc/[pid]/status能夠查看進程的內存使用狀況,包括虛擬內存大小(VmSize),物理內存大小(VmRSS),數據段大小(VmData),棧的大小(VmStk),代碼段的大小(VmExe),共享庫的代碼段大小(VmLib)等等。java
* Name: java /*進程的程序名*/ * State: S (sleeping) /*進程的狀態信息,具體參見*/ * Tgid: 9744 /*線程組號*/ * Pid: 9744 /*進程pid*/ * PPid: 7672 /*父進程的pid*/ * TracerPid: 0 /*跟蹤進程的pid*/ * VmPeak: 60184 kB /*進程地址空間的大小*/ * VmSize: 60180 kB /*進程虛擬地址空間的大小reserved_vm:進程在預留或特殊的內存間的物理頁*/ * VmLck: 0 kB /*進程已經鎖住的物理內存的大小.鎖住的物理內存不能交換到硬盤*/ * VmHWM: 18020 kB /*文件內存映射和匿名內存映射的大小*/ * VmRSS: 18020 kB /*應用程序正在使用的物理內存的大小,就是用ps命令的參數rss的值 (rss)*/ * VmData: 12240 kB /*程序數據段的大小(所佔虛擬內存的大小),存放初始化了的數據*/ * VmStk: 84 kB /*進程在用戶態的棧的大小*/ * VmExe: 576 kB /*程序所擁有的可執行虛擬內存的大小,代碼段,不包括任務使用的庫 */ * VmLib: 21072 kB /*被映像到任務的虛擬內存空間的庫的大小*/ * VmPTE: 56 kB /*該進程的全部頁表的大小*/ * Threads: 1 /*共享使用該信號描述符的任務的個數*/
java內存組成介紹:堆(Heap)和非堆(Non-heap)內存
按照官方的說法:「Java 虛擬機具備一個堆,堆是運行時數據區域,全部類實例和數組的內存均今後處分配。堆是在 Java 虛擬機啓動時建立的。」 「在JVM中堆以外的內存稱爲非堆內存(Non-heap memory)」。nginx
能夠看出JVM主要管理兩種類型的內存:堆和非堆。算法
簡單來講堆就是Java代碼可及的內存,是留給開發人員使用的;非堆就是JVM留給本身用的。數組
因此方法區、JVM內部處理或優化所需的內存(如JIT編譯後的代碼緩存)、每一個類結構(如運行時常數池、字段和方法數據)以及方法和構造方法 的代碼都在非堆內存中。瀏覽器
JVM 自己須要的內存,包括其加載的第三方庫以及這些庫分配的內存緩存
NIO 的 DirectBuffer 是分配的 native memory服務器
內存映射文件,包括 JVM 加載的一些 JAR 和第三方庫,以及程序內部用到的。上面 pmap 輸出的內容裏,有一些靜態文件所佔用的大小不在 Java 的 heap 裏,所以做爲一個Web服務器,趕忙把靜態文件從這個Web服務器中人移開吧,放到nginx或者CDN裏去吧。app
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=512Mjvm
JNI,一些JNI接口調用的native庫也會分配一些內存,若是遇到JNI庫的內存泄露,可使用valgrind等內存泄露工具來檢測ide
線程棧,每一個線程都會有本身的棧空間,若是線程一多,這個的開銷就很明顯了
也稱」永久代」 、「非堆」,它用於存儲虛擬機加載的類信息、常量、靜態變量、是各個線程共享的內存區域。默認最小值爲 16 MB,最大值爲 64 MB,能夠經過-XX: PermSize 和 -XX: MaxPermSize 參數限制方法區的大小。
運行時常量池:是方法區的一部分,Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用於存放編譯器生成的各類符號引用,這部份內容將在類加載後放到方法區的運行時常量池中。
描述的是java 方法執行的內存模型:每一個方法被執行的時候 都會建立一個「棧幀」用於存儲局部變量表(包括參數)、操做棧、方法出口等信息。
每一個方法被調用到執行完的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。聲明週期與線程相同,是線程私有的。
局部變量表存放了編譯器可知的各類基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(引用指針,並不是對象自己),其中64位長度的long和double類型的數據會佔用2個局部變量的空間,其他數據類型只佔1個。
局部變量表所需的內存空間在編譯期間完成分配,當進入一個方法時,這個方法須要在棧幀中分配多大的局部變量是徹底肯定的,在運行期間棧幀不會改變局部變量表的大小空間。
與虛擬機棧基本相似,區別在於虛擬機棧爲虛擬機執行的java方法服務,而本地方法棧則是爲Native方法服務。
也叫作java 堆、GC堆是java虛擬機所管理的內存中最大的一塊內存區域,也是被各個線程共享的內存區域,在JVM啓動時建立。
該內存區域存放了對象實例及數組(全部 new 的對象)。其大小經過 -Xms (最小值) 和 -Xmx (最大值) 參數設置,-Xms爲 JVM 啓動時申請的最小內存,默認爲操做系統物理內存的 1/64 但小於 1G;
-Xmx 爲 JVM 可申請的最大內存,默認爲物理內存的1/4但小於 1G,默認當空餘堆內存小於 40% 時,JVM 會增大 Heap 到 -Xmx 指定的大小,可經過 -XX:MinHeapFreeRation= 來指定這個比列;
當空餘堆內存大於70%時,JVM 會減少 heap 的大小到 -Xms 指定的大小,可經過XX:MaxHeapFreeRation= 來指定這個比列,對於運行系統,爲避免在運行時頻繁調整 Heap 的大小,一般 -Xms 與 -Xmx 的值設成同樣。
因爲如今收集器都是採用分代收集算法,堆被劃分爲新生代和老年代。新生代主要存儲新建立的對象和還沒有進入老年代的對象。老年代存儲通過屢次新生代GC(Minor GC)任然存活的對象。
是最小的一塊內存區域,它的做用是當前線程所執行的字節碼的行號指示器,在虛擬機的模型裏,字節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令,分支、循環、異常處理、線程恢復等基礎功能都須要依賴計數器完成。
直接內存並非虛擬機內存的一部分,也不是Java虛擬機規範中定義的內存區域。jdk1.4中新加入的NIO,引入了通道與緩衝區的IO方式,它能夠調用Native方法直接分配堆外內存,這個堆外內存就是本機內存,不會影響到堆內存的大小。
[root@server ~]$ jmap -heap 837 Attaching to process ID 837, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.71-b01 using thread-local object allocation. Parallel GC with 4 thread(s)//GC 方式 Heap Configuration: //堆內存初始化配置 MinHeapFreeRatio = 0 //對應jvm啓動參數-XX:MinHeapFreeRatio設置JVM堆最小空閒比率(default 40) MaxHeapFreeRatio = 100 //對應jvm啓動參數 -XX:MaxHeapFreeRatio設置JVM堆最大空閒比率(default 70) MaxHeapSize = 2082471936 (1986.0MB) //對應jvm啓動參數-XX:MaxHeapSize=設置JVM堆的最大大小 NewSize = 1310720 (1.25MB)//對應jvm啓動參數-XX:NewSize=設置JVM堆的‘新生代’的默認大小 MaxNewSize = 17592186044415 MB//對應jvm啓動參數-XX:MaxNewSize=設置JVM堆的‘新生代’的最大大小 OldSize = 5439488 (5.1875MB)//對應jvm啓動參數-XX:OldSize=<value>:設置JVM堆的‘老生代’的大小 NewRatio = 2 //對應jvm啓動參數-XX:NewRatio=:‘新生代’和‘老生代’的大小比率 SurvivorRatio = 8 //對應jvm啓動參數-XX:SurvivorRatio=設置年輕代中Eden區與Survivor區的大小比值 PermSize = 21757952 (20.75MB) //對應jvm啓動參數-XX:PermSize=<value>:設置JVM堆的‘永生代’的初始大小 MaxPermSize = 85983232 (82.0MB)//對應jvm啓動參數-XX:MaxPermSize=<value>:設置JVM堆的‘永生代’的最大大小 G1HeapRegionSize = 0 (0.0MB) Heap Usage://堆內存使用狀況 PS Young Generation Eden Space://Eden區內存分佈 capacity = 33030144 (31.5MB)//Eden區總容量 used = 1524040 (1.4534378051757812MB) //Eden區已使用 free = 31506104 (30.04656219482422MB) //Eden區剩餘容量 4.614088270399305% used //Eden區使用比率 From Space: //其中一個Survivor區的內存分佈 capacity = 5242880 (5.0MB) used = 0 (0.0MB) free = 5242880 (5.0MB) 0.0% used To Space: //另外一個Survivor區的內存分佈 capacity = 5242880 (5.0MB) used = 0 (0.0MB) free = 5242880 (5.0MB) 0.0% used PS Old Generation //當前的Old區內存分佈 capacity = 86507520 (82.5MB) used = 0 (0.0MB) free = 86507520 (82.5MB) 0.0% used PS Perm Generation//當前的 「永生代」 內存分佈 capacity = 22020096 (21.0MB) used = 2496528 (2.3808746337890625MB) free = 19523568 (18.619125366210938MB) 11.337498256138392% used 670 interned Strings occupying 43720 bytes.
前面jmap輸出的內容裏,MaxHeapSize 是在命令行上配的,-Xmx4096m,這個java程序能夠用到的最大堆內存。
VSZ是指已分配的線性空間大小,這個大小一般並不等於程序實際用到的內存大小,產生這個的可能性不少,好比內存映射,共享的動態庫,或者向系統申請了更多的堆,都會擴展線性空間大小,要查看一個進程有哪些內存映射,可使用 pmap 命令來查看:
pmap -x [pid]
[root@server ~]$ 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的內存組成分別爲:
jstat -gcutil [pid]
[root@server ~]$ 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
分析 JVM 堆內存中的對象
jmap -histo:live [pid]
jmap -dump:format=b,file=heapDump [pid]
jhat -port 5000 heapDump
在瀏覽器中訪問:http://localhost:5000/ 查看詳細信息