一份關於jvm內存調優及原理的學習筆記

JVMjava

 

一.虛擬機的基本結構算法

 

1.jvm總體架構sql

 

 

類加載子系統:負責從文件系統或者網絡中加載class信息,存入方法區中。服務器

方法區(Perm):存放加載後的class信息,包括靜態方法,jdk1.6之前包含了常量池。網絡

參數:-XX:PermSize初始值  -XX:MaxPermSize最大值數據結構

 

Java堆(Heap):java工程的主要內存工做區域,全部線程共享,jdk1.7之後包含了常量池。參數: -Xms初始值     -Xmx最大值多線程

 

直接內存:java堆外,直接向系統申請的內存區間,容許NIO庫使用。申請空間慢,讀寫快。默認下最大可用空間等於堆的最大可用空間。在server模式下,讀寫速度是堆的10倍。架構

參數:-XX:MaxDirectMemorySize 最大值jvm

 

垃圾回收器:函數

 

Java棧:線程私有,用於存放局部變量,方法參數,同時和java方法的調用返回密切相關。

參數:-Xss最大值

 

本地方法棧:和java棧相似,主要用於本地方法調用。

PC寄存器:線程私有

執行引擎:

 

 

Java [-options] class [args...]

其中-options是java虛擬機的啓動參數,args是傳遞給main方法的參數、

 

 

2.java堆

根據垃圾回收機制的不一樣,java堆有可能擁有不一樣的結構,常見的java堆分爲新生代和老年代。其中新生代存放剛建立的對象及年齡不大的對象,老年帶存放着在新生代中經歷過屢次回收後還存在的對象。

 

 

 

對象晉升過程:

新生代分爲eden區s0,s1區(from,to)。多數狀況下對象首先分配在eden區,在一次新生代回收後,存活下來的對象存入s0或s1區。每通過一次新生代的回收,對象的年齡加1。默認狀況下年齡達到15的對象將晉升至老年代。若是在第一次回收的時候,存活的對象大於s0(s1)空間,將直接晉升至老年代,若是在爲對象第一次分配空間時,對象空間大於eden空間的話,對象也直接分配到老年代。

 

 

3.java棧

Java棧和數據結構中的棧有着相似的含義,先進後出,只支持入棧和出棧操做。Java棧中保存的只要內容是棧幀,每一次進行函數調用,都會有一個對應的棧幀被壓入棧中,函數調用結束,都會有一個棧幀被彈出棧。

 

 

棧幀

每個棧幀中包含局部變量表,操做數棧和幀數據區。

棧上分配

棧上分配的基本思想,是將線程私有的對象,打散分配到棧上,分配在棧上的函數調用結束後對象會自行銷燬,不須要垃圾回收接入,從而提高性能。對於大量的零散小對象,棧上分配提供了一種很好的對象分配優化策略,但因爲和堆空間相比,棧空間較小,所以大對象沒法也不適合在棧上分配

棧上分配依賴逃逸分析和標量替換的實現,同時必須在server模式下才能啓用。參數-XX:+DoEscapeAnalysis啓用逃逸分析     -XX:+EliminateAllocations開啓標量替換(默認打開).

例:-server -Xms 100m -Xmx 100m -XX:+DoEscapeAnalysis -XX:+EliminateAllocations

 

 

二.Jvm經常使用參數

 

1.GC參數

-XX:+PrintGC    每次觸發GC的時候打印相關日誌

-XX:+PrintGCDetails    更詳細的GC日誌

-XX:+PrintHeapAtGC    每次GC時打印堆的詳細詳細信息

-XX:+PrintGCApplicationConcurrentTime    打印應用程序執行時間

-XX:+PrintGCApplicationAtoppedTime    打印應用程序由GC引發的停頓時間

-XX:+PrintReferenceGC    跟蹤系統內的軟引用,弱引用,虛引用和finallize隊列。

 

 

1.類跟蹤

-verbose:class    跟蹤類的加載和卸載

-XX:+TraceClassLoading    單獨跟蹤類加載

-XX:+TraceClassUnloading    單獨跟蹤類卸載

-XX:+PrintClassHistogram    查看運行時類的分佈狀況,使用時在控制檯按ctrl+break

 

 

2.系統參數查看

-XX:+PrintVMOptions       運行時,打印jvm接受的命令行顯式參數

-XX:+PrintCommandLineFlags    打印傳遞jvm的顯式和隱式參數

-XX:+PrintFlagsFinal    打印全部系統參數值

 

 

3.堆

-Xms    堆初始值

-Xmx    堆最大可用值

-Xmn    新生代大小,通常設爲整個堆的1/3到1/4左右

-XX:SurvivorRatio    設置新生代中eden區和from/to空間的比例關係n/1

-XX:NewRatio    設置老年代與新生代的比

 

想要合理的分配堆內存,須要瞭解對象的晉升過程,能夠參照上面介紹堆空間架構時,對對象晉升過程的描述。

 

 

基本策略:堆的不一樣分佈狀況,對系統會產生必定的影響。儘量將對象預留在新生代,減小老年代GC的次數(一般老年回收起來比較慢)。實際工做中,一般將堆的初始值和最大值設置相等,這樣能夠減小程序運行時進行的垃圾回收次數和空間擴展,從而提升程序性能。

 

4.非堆

-XX:PermSize   方法區(永久區)初始值

-XX:MaxPermSize    方法區(永久區)最大值

-Xss    設置棧空間大小

-XX:MaxDirectMemorySize    直接內存最大可用空間,設置不當可能致使系統OOM

 

5.虛擬機工做模式

-client    默認工做模式

-server    server工做模式,啓動虛擬機時須要顯式指定

與client模式相比,server模式啓動較慢,會嘗試蒐集更多的系統性能信息,使用更復雜的優化算法對程序進行優化,server模式下系統徹底啓動並進入穩按期後,執行速度遠遠快於client模式,適合長期後臺運行的系統。Client模式更適合運行時間不長,又追求啓動速度的客戶端程序。

 

 

三.Jvm性能監控工具

1.JConsole

內存監控,線程監控,類加載狀況,虛擬機信息

2.Visual VM

線程dump和分析,性能分析,內存快照分析,BTrace

3.Mission Control

MBean服務器,飛行記錄器

 

四.分析java堆

1.常見的內存溢出緣由及解決思路

(1)堆溢出:設置-Xmx調整最大可用堆空間

 

(2)直接內存溢出:多是系統內存空間不足,同時沒達到參數默認的上限,沒有觸發GC致使OOM,解決方法是經過-XX:MaxDirectMemorySize 來限制最大內存。

 

(3)過多線程致使OOM:因爲每開啓一個線程都會給這個線程分配一個棧,所以當線程數達到必定程度,系統空間不足的時候就會內存溢出,能夠嘗試減小堆空間,或者能夠經過設置參數-Xss限制每一個棧的大小。

 

(4)永久區溢出:系統加載的類過多,致使永久區溢出,經過-XX:MaxPermSize來設置永久區最大可用空間。

 

(5)GC效率低下引發的OOM:GC是內存回收的關鍵,回收效率低頗有可能引發內存溢出,能夠經過合理的分配堆(包括新生代和老年代)空間去解決。

 

 

2.String形成的內存泄漏

內存泄漏是指,再也不使用的對象佔據內存不釋放,致使可用內存不斷減少,最終引發內存泄漏。在Java1.6中String.subString()方法就存在這樣的問題。

SubString中新生成的對象並無從value中獲取本身須要的那部分,而是直接簡單的使用了相同的引用,只是修改了offset和count,以此來肯定新的String對象的值。當原始字符串還在用的時候這種狀況是沒有問題的,而且共用value還節省了部分的空間,可是一旦原始字符串被回收,value中多餘的部分就形成了空間浪費。

 

3.淺堆和深堆

淺堆:是指一個對象自己所消耗的內存,不包括其內部引用的對象的大小。

深堆:是指對象的保留集中全部對象淺堆的大小之和。

保留集:是指當對象A被垃圾回收後,能夠釋放的全部對象的集合(包括A自己),通俗的講就是,僅被對象A所持有的對象的集合。

 

4.OQL查詢語句

相似於sql語法的查詢語句,能夠在堆中進行對象的查找和篩選。

......

 

 

相關文章
相關標籤/搜索