国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JVM的基本概念與維護調優(yōu)

DevWiki / 2005人閱讀

摘要:棧因為是運行單位,因此里面存儲的信息都是跟當前線程相關的信息。基本類型和對象的引用都是在存放在棧中,而且都是幾個字節(jié)的一個數,因此在程序運行時,他們的處理方式是統一的。對象,是由基本類型組成的。

一、概念 數據類型

java虛擬機中,數據類型可以分為兩類:

基本類型
引用類型

基本類型的變量保存原始值,即:他代表的值就是數值本身;而引用類型的變量保存引用值。
基本類型包括:byte,short,int,long,float,double,Boolean

“引用值”代表了某個對象的引用,而不是對象本身,對象本身存放在這個引用值所表示的地址位置。
引用類型包括:類的類型,接口類型和數組

堆與棧
棧是運行時單位
堆是存儲單位

棧解決程序的運行問題,即程序如何執(zhí)行,或者說如何處理數據;堆解決的是數據存儲問題,即數據怎么放,放在哪

在java中一個線程就會相應有一個線程棧與之對應,這點很容易理解,因為不同的線程執(zhí)行邏輯有所不同,因此需要一個獨立的線程棧。而堆則是所有線程共享的。棧因為是運行單位,因此里面存儲的信息都是跟當前線程相關的信息。包括局部變量、程序運行狀態(tài)、方法返回值等;而堆只負責存儲對象信息

為什么要把堆和棧區(qū)分出來呢?棧中不是也可以存儲數據嗎?

從software設計角度來看,棧代表了處理邏輯,而堆代表了數據。這樣分開,使得處理邏輯更為清晰。分而治之思想。這種隔離,模塊化思想在軟件設計的方面都有體現。

堆與棧的分離,使得堆中的內容可以被多個棧共享(也可以理解為多個線程訪問同一個對象)。這種共享的收益很多的。一方面這種共享提供了一種有效的數據交互方式(共享內存),另一方面,堆中的共享常量和緩存可以被所有棧訪問,節(jié)省了空間

棧因為運行時的需要,比如保存系統運行上下文,需要進行地址段的劃分。由于棧只能向上增長,因此就會限制住棧存儲內容的能力。而堆不同,堆中的對象是可以根據需要動態(tài)增長的,因此棧和堆的拆分,使得動態(tài)增長成為可能,相應棧中只需要記錄堆中的一個地址即可

面向對象就是堆和棧的完美結合。其實,面向對象方式的程序與以前結構化的程序在執(zhí)行上沒有任何區(qū)別。但是,面向對象的引入,使得對待問題的思考方式發(fā)生了改變,而更接近于自然方式的思考。當我們把對象拆開,你會發(fā)現,對象的屬性其實就是數據,存放在堆中;而對象的行為(方法),就是運行邏輯,放在棧中。我們在編寫對象的時候,其實即編寫了數據結構,也編寫了處理數據的邏輯。不得不承認,面向對象的設計,確實完美。

堆中存什么?棧中存什么?
堆中存對象
棧中存最基本數據類型和堆中對象的引用

一個對象的大小是不可估計的,或者說是可估計的,或者說是可以動態(tài)改變的,但在棧中,一個對象只對應4byte的引用

為什么不把基本類型放堆中呢?

因為其占用的空間一般是1~8個字節(jié),需要空間比較少,而且因為是基本類型,所以不會出現動態(tài)增長的情況,長度固定,因此棧中存儲就夠了,如果把他存在堆中是沒什么意義的。可以說是浪費。基本類型和對象的引用都是在存放在棧中,而且都是幾個字節(jié)的一個數,因此在程序運行時,他們的處理方式是統一的。但是基本類型、對象引用和對象本身就是有所區(qū)別的,因為一個棧中的數據一個是堆中的數據。最常見的一個問題就是,java中參數傳遞時的問題。

java中的參數傳遞時傳值呢?還是傳引用?

不要試圖與C進行類比,java中沒有指針的概念

程序運行永遠都是在棧中進行的,因而參數傳遞時,只存在傳遞基本類型和對象引用的問題。不會直接傳對象本身。

java在方法調用傳遞參數時,因為沒有指針,所以它都是進行傳值調用。因此,很多書里面都說java是進行傳值調用,這點沒有問題,而且也簡化了C中的復雜性。

但是傳引用的錯覺是如何造成的呢?

在運行棧中,基本類型和引用的處理都是一樣的,都是傳值,所以,如果是傳引用的方法調用,也同時可以理解為“傳引用值”的傳值調用,即引用的處理跟基本類型是完全不一樣的。但是當進入被調用方法時,被傳遞的這個引用的值,被程序解釋到堆中的對象,這個時候才對應到真正的對象,如果此時進行修改,修改的是引用對應的對象,而不是引用本身,即修改的是堆中的數據。所以這個修改是可以保持的了。

對象,是由基本類型組成的。可以把一個對象看做成一棵樹,對象的屬性如果還是對象,則還是一棵樹(即非葉子節(jié)點),基本類型則為樹的葉子節(jié)點。程序參數傳遞時,被傳遞的值本身都是不能進行修改的,但是,如果這個值是一個非葉子節(jié)點(即一個對象引用),則可以修改這個節(jié)點下面的所有內容。

堆和棧中,棧是程序運行最根本的東西。程序運行可以沒有堆,但不能沒有棧。而堆是為棧進行數據存儲服務,說白了堆就是一塊共享的內存。不過,正是因為堆和棧的分離的思想,才使得java的垃圾回收成為可能

java中,棧的大小通過-Xss來設置,當棧中存儲的數據比較多時,需要適當調大這個值,否則會出現java.lang.StackOverflowError異常。常見的出現這個異常的是無法返回的遞歸,因為此時棧中保存的信息都是方法返回的記錄點。

引用類型

對象引用類型分為:

強引用
軟引用
弱引用和虛引用

強引用:就是我們一般聲明對象是時虛擬機生成的引用,強引用環(huán)境下,垃圾回收時需要嚴格判斷當前對象是否被強引用,如果被強引用,則不會被垃圾回收

軟引用:軟引用一般被做為緩存來使用。與強引用的區(qū)別是,軟引用在垃圾回收時,虛擬機會根據當前系統的剩余內存來決定是否對軟引用進行回收。如果剩余內存比較緊張,則虛擬機會回收軟引用所引用的空間:如果剩余內存相對富裕,則不會進行回收。換句話說,虛擬機在發(fā)生OutOfMemory時,肯定是沒有軟引用存在的

弱引用:弱引用與軟引用類似,都是作為緩存來使用。但與軟引用不同,弱引用在進行垃圾回收時,是一定會被回收掉的,因此其生命周期只存在于一個垃圾回收周期內。

強引用是我們系統一般在使用時都是用的強引用。而“軟引用”和“弱引用”比較少見。他們一般被作為緩存使用,而且一般是在內存大小比較受限的情況下做為緩存。因為如果內存足夠大的話,可以直接使用強引用作為緩存即可,同時可控性更高。因而,他們常見的是被使用在桌面應用系統的緩存

二、基本垃圾回收算法

此算法結合了“標記-清除”“復制”兩個算法的優(yōu)點。
也是分兩階段:
第一階段從根節(jié)點開始標記所有被引用對象。
第二階段遍歷整個堆,把清除未標記對象并且把存活對象“壓縮”到堆的其中一塊,按順序排放。此算法避免了“標記-請除”的碎片問題,同時也避免了“復制”算法的空間問題。

按系統線程分

串行收集:串行收集使用單線程處理所有垃圾回收工作,因為無需多線程交互,實現容易而且效率比較高,但是,其局限性也比較明顯,即無法使用多處理器的優(yōu)勢,所以此收集通過單處理器機器。當然,此收集器也可以用在小數據量(100M左右)情況下的多處理器機機器上。

并行收集:并行收集使用多線程處理垃圾回收工作,因而速度快,效率高。而且理論上CPU數目越多,越能體現出并行收集器的優(yōu)勢

并發(fā)收集:相對于串行收集和并行收集而言,前面兩個在進行垃圾回收工作時,需要暫時停止整個運行環(huán)境,而只有垃圾回收程序在運行,因此,系統在垃圾回收時會有明顯的暫停,而且暫停時間會因為堆越大而越長

三、垃圾回收面臨的問題 如何區(qū)分垃圾?

上面說到的“引用計數”法,通過統計控制生成對象和刪除對象時的引用數來判斷。垃圾回收程序收集計數為0的對象即可。但是這種方法無法解決循環(huán)引用。所以,后來實現的垃圾判斷算法中,都是從程序運行的根節(jié)點出發(fā),遍歷整個對象引用,查找存活的對象。那么在這種方式的實現中,垃圾回收從哪兒開始的呢?從哪兒開始查找哪些對象是正在被當前系統使用的,上面分析的堆和棧的區(qū)別,其中棧是真正進行程序執(zhí)行地方,所以要獲取哪些對象正在被使用,則需要從Java棧開始。同時,一個棧是與一個線程對應的,因此,如果有多個線程的話,則必須對這些線程對應的所有的棧進行檢查

同時,除了棧外,還有系統運行時的寄存器等,也是存儲程序運行數據的。這樣,以棧或寄存器中的引用為起點,我們可以找到堆中的對象,又從這些對象找到對堆中其他對象的引用,這種引用逐步擴展,最終以null引用或者基本類型結束,這樣就形成了一顆以Java棧中引用所對應的對象為根節(jié)點的一顆對象樹,如果棧中有多個引用,則最終會形成多顆對象樹。在這些對象樹上的對象,都是當前系統運行所需要的對象,不能被垃圾回收。而其他剩余對象,則可以視為無法被引用到的對象,可以被當做垃圾進行回收。

因此,垃圾回收的起點是一些根對象(java棧,靜態(tài)變量,寄存器)。而最簡單的Java棧就是Java程序執(zhí)行的main函數。這種回收方式,也是上面提到的“標記-請除”的回收方式。

如何處理碎片?

由于不同Java對象存活時間是不一定的,因此,在程序運行一段時間以后,如果不進行內存整理,就會出現零散的內存碎片。碎片最直接的問題就是會導致無法分配大塊的內存空間,以及程序運行效率降低。所以,在上面提到的基本垃圾回收算法中,“復制”方式和“標記-整理”方式,都可以解決碎片的問題.

如何解決同時存在的對象創(chuàng)建和對象回收問題?

垃圾回收線程是回收內存的,而程序運行線程則是消耗(或分配)內存的,一個回收內存,一個分配內存,從這點看,兩者是矛盾的。因此,在現有的垃圾回收方式中,要進行垃圾回收前,一般都需要暫停整個應用(即暫停內存的分配),然后進行垃圾回收,回收完成后再繼續(xù)應用。這種實現方式是最直接,而且最有效的解決一者矛盾的方式。但是這種方式有一個很明顯的弊端,就是當堆空間持續(xù)增大時,垃圾回收的時間也將會相應的持續(xù)增大,對應應用暫停的時間也會相應的增大。一些對相應時間要求很高的應用,比如最大暫停時間要求是幾百毫秒,那么當堆空間大于幾個G時,就很有可能超過這個限制,在這種情況下,垃圾收將會成為系統運行的一個瓶頸。為解決這種矛盾,有了并發(fā)垃圾回收算法,使用這種算法,垃圾回收線程與程序運行線程同時運行。在這種方式下,解決了暫停的問題,但是因為需要在新生成對象的同時又要回收對象,算法復雜性會大大增加,系統的處理能力也會相應降低,同時,“碎片”問題將會比較難解決

四、分代垃圾回收詳述 為什么要分代?

分代的垃圾回收策略,是基于這樣一個事實:不同的對象的生命周期是不一樣的。因此,不同生命周期的對象可以采取不同的收集方式,以便提高回收效率。在Java程序運行的過程中,會產生大量的對象,其中有些對象是與業(yè)務信息相關,比如Http?請求中的Session對象、線程、Socket連接,這類對象跟業(yè)務直接掛鉤,因此生命的周期比較長,但是還有一些對象,主要是程序運行過程中生成的臨時變量,這些對象生命周期會比較短,比如:String對象,由于其不變類的特性,系統會產生大量的這些對象,有些對象甚至只用一次即可回收。

試想,在不進行對象存活時間區(qū)分的情況下,每次垃圾回收都是對整個堆空間進行回收,花費時間相對會長,同時,因為每次回收都需要遍歷所有存活對象,但實際上,對于生命周期長的對象而言,這種遍歷是沒有效果的,因為可能進行了很多次通歷,但是他們依舊存在因此,分代垃圾回收采用分治的思想,進行代的劃分,把不同生命周期的對象放在不同代上,不同代上采用最適合它的垃圾回收方式進行回收。

虛擬機中的共劃分為三個代:

年輕代(Young?Generation)
年老代(Old?Generation)
持久代(Permanent?Generation)

其中持久代主要存放的是Java類的類信息,與垃圾收集要收集的Java對象關系不大。年輕代和年老代的劃分是對垃圾收集影響比較大的。

年輕代:所有新生成的對象首先都是放在年輕代的。年輕代的目標就是盡可能快速的收集掉那些生命周期短的對象。年輕代分三個區(qū):1個Eden區(qū),2個Survivor區(qū)(一般而言)。大部分對象在Eden區(qū)中生成,當Eden區(qū)滿時,還存活的對象將被復制到Survivor區(qū)(兩個中的一個),當這個Survivor區(qū)滿時,此區(qū)的存活對象將被復制到另外一個Survivor區(qū),當這個Survivor區(qū)也滿了的時候,從第一個Survivor區(qū)復制過來的并且此時還存活的對象將被復制“年老區(qū)(Tenured)”。需要注意,Survivor的兩個區(qū)是對稱的,沒先后關系,所以同一個區(qū)中可能同時存在從Eden復制過來對象,和從前一個Survivor復制過來的對象,而復制到年老區(qū)的只有從第一個Survivor區(qū)過來的對象。而且,Survivor區(qū)總有一個是空的。同時,根據程序需要,Survivor區(qū)是可以配置多個的,這樣可以增加對象在年輕代中存在的時間,減少被放到老代的可能。

年老代:在年輕代中經歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中,因此,可認為年老代中存放的都是一些生命周期較長的對象

持久代:用于存放靜態(tài)文件,java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態(tài)生成或調用一些class,例如Hibernate等,在這種時候需要設置一個比較大的持久代空間來存放這些運行過程中新增的類,持久代大小通過-XX:MaxPermSize=進行設置。

什么情況下觸發(fā)垃圾回收?

由于對像進行了分代處理,因此垃圾回收區(qū)域、時間也不一樣。GC有兩種類型:

Scavenge?GC
Full?Gc

Scavenge?GC:一般情況下,當新對象生成,并且在Eden申請空間失敗時,就會觸發(fā)?Scavenge?GC,對Eden區(qū)域進行GC,清除非存活對象,并且把尚且存活的對象移動到Survivor區(qū),然后整理Survivor的兩個區(qū)。這種方式的GC是對年輕代的Eden區(qū)進行,不會影響到年老代。因為大部分對象都是從Eden區(qū)開始的,同時Eden區(qū)不會分配的很大,所以Eden區(qū)的GC會須繁進行。因而,一般在這里需要使用速度快、效率高的算法,使Eden去能盡快空閑出來。

Full GC:對整個堆進行整理,包括Young、Tenured和Perm。Full GC因為需要對整個堆進行回收,所以比Scavenge GC要慢,因此應該盡可能減少Full GC的次數。在對JVM調優(yōu)的過程中,很大一部分工作就是對于Full GC的調節(jié)。有如下原因可能導致Full GC:

年老代(Tenured)被寫滿

持久代(Perm)被寫滿

System.gc()被顯示調用

上一次GC之后Heap的個域分配策略動態(tài)變化

選擇合適的垃圾收集算法

串行收集器:用單線程處理所有垃圾回收工作,因為無需多線程交互,所以效率比較高。但是,也無法使用多處理器的優(yōu)勢,所以此收集器適合單處理器機器。當然,此收集器也可以用在小數據量(100M左右)情況下的多處理器機器上。可以使用-XX:+UseSerialGC打開。

并行收集器:對年輕代進行井行垃圾回收,因此可以減少垃圾回收時間。一般在多線程多處理器機器上使用。使用-XX:+UseParallelGC打開,并行收集器在J2SE5.0第六6更新上引入,在JavaSE6.0中進行了增強,可以對年老代進行并行收集,如果年老代不使用并發(fā)收集的話,默認是使用單線程進行垃圾回收,因此會制約擴展能力。使用XX:+UseParalelOldGC打開并行收集器收集年老代,使用-XX:ParalelGCThreads=設置并行垃圾回收的線程數。

此收集器可以進行如下配置:
最大垃圾回收暫停:指定垃圾回的時的最長暫停時間,通討-XX:MaxGCPauseMilis=指定。為毫秒,如果指定了此值的話,堆大小和垃圾回收相關參數會進行調整以達到指定值。設定此值可能會減少應用的吞吐量。
吞吐量:吞吐量為垃圾回收時間與非垃圾回收時間的比值,通過-XX:GCTimeRatio=來設定,公式為1/(1+N)。例如,-XX:GCTimeRatio=19時,表示5%的時間用于垃圾回收。默認情況為99,即1%的時間用于垃圾回收。

并發(fā)收集器可以保證大部分工作都并發(fā)進行(應用不停止),垃圾回收只暫停很少的時間,此收集器適合對響應時間要求比較高的中、大規(guī)模的應用。使用-XX:+UseConcMarkSweepGC打開。

并發(fā)收集器主要減少年老代的暫停時間,他在應用不停止的情況下使用獨立的垃圾回收線程,跟蹤可達對象。在每個年老代垃圾回收周期中,在收集初期并發(fā)收集器會對整個應用進行簡短的暫停,在收集中還會再暫停一次。第二次暫停會比第一次稍長,在此過程中多個線程同時進行垃圾回收工作。并發(fā)收集器使用處理器短暫的停頓時間。在一個N個處理器的系統上,并發(fā)收集部分使用KWN個可用處理器進行回收,一般情況下1<=K<=N/4。在只有一個處理器的主機上使用并發(fā)收集器,設置為incrementalmode?模式也可獲得較短的停頓時間。

浮動垃圾:由于在應用運行的同時進行垃圾回收,所以有些垃圾可能在拉圾回收進行完成時產生,這樣就造成了“Floating?Garbage”,這些垃圾需要在下次拉圾回收周期時才能回收掉,所以,并發(fā)收集器一般需要20%的預留空間用于這些浮動垃圾。

Concurrent?Mode?Failure:并發(fā)收集器在應用運行時進行收集,所以需要保證堆在垃圾回收的這段時間有足夠的空間供程序使用,否則,垃圾回收還未完成,堆空間先滿了。這種情況下將會發(fā)生“并發(fā)模式失敗”,此時整個應用將會暫停,進行垃極回收。

啟動并發(fā)收集器:因為并發(fā)收集在應用運行時進行收集,所以必須保證收集完成之前足夠的內存空間供程序使用,否則會出現“Concurrent?Mode?Failure”.通過設置XX:CMSInitiatingOccupancyFraction=指定還有多少剩余堆時開始執(zhí)行并發(fā)收集。

小結

串行處理器:
適用情況:數據量比較小(100M左右):單處理器下并且對響應時間無要求的應用。
缺點:只能用于小型應用。

并行處理器:
適用情況:“對吞吐量有高要求”,多CPU、對應用響應時間花裝求的中、大型應用。舉例:后臺處理、科學計算。
缺點:垃圾收集過程中應用響應時間可能加長。

并發(fā)處理器:
適用情況:“對響應時間有高要求”,多CPU、對應用響應時間有較高要求的中、大型應用。舉例:Web服務器/應用服務器、電信交換、集成開發(fā)環(huán)境。

五、常見配置匯總 堆設置

-Xms:初始堆大。
-Xmx:最大堆大小。
初始堆大小與最大堆大小盡量小于4G。兩值不相等的話,內存地址中會計算會對應用程序產生影響,索性設為相等。

-XX:NewSize=n:設置年輕代大小。
-XX:NewRatio=n:設置年輕代和年老代的比值。如:為3,表示年輕代與年老代比值為1:3,年輕代占整個年輕代年老代的1/4。
-XX:SurvivorRatio=n:年輕代中Eden區(qū)與連個Survivor區(qū)的比值。注意Survivor區(qū)有兩個。如:3,表示Eden:Survivor=3:2,一個Survivor區(qū)占整個年代的1/5。
-XX:MaxPermSize=n:設置持久代大小。

收集器設置

-XX:+UseSerialGC:設置串行。
-XX:+UseParallelGC:設置并行。
-XX:+UseParalledlOldGC:設置并行年老代。
-XX:+UseConcMarkSweepGC:設置并發(fā)。

垃圾回收統計信息

-XX:+PrintGC:輸出GC日志。
-XX:+PrintGCDetails:輸出GC的詳細日志。
-XX:+PrintGCTimeStamps:輸出GC的時間戳(以基準時間的形式)。
-Xloggc:filename:日志文件的輸出路徑。

并發(fā)收集器設置

-XX:ParallelGCThreads=n:設置并行收集器收集使用的CPU數。并行收集線程數。
-XX:MaxGCPauseMillis=n:設置并行收集最大暫停時間。
-XX:GCTimeRatio=n:設置垃圾回收時間占程序運行時間的百分比。公式1/(1+n)。
-XX:+CMSlncrementalMode:設置為增量模式。適用于單CPU情況。
-XX:ParallelGCThreads=n:設置并發(fā)收集器年期代收集方式,使用的CPU數。并行收集線程。

六、典型配置舉例 堆大小設置

JVM中最大堆大小有三方面限制:相關操作系統的數據模型(32bit還是64bit)限制;系統的可用虛擬內存限制;系統的可用物理內存限制。32位系統下,一般限制在1.5G~2G;64位操作系統對內存無限制。在Windows Server 2003系統,3.5G物理內存,JDK5.0下測試,最大可設置為1478m

典型設置:

java -Xms3550m -Xmx3550m -Xmn2G -Xss128k

-Xmx3550m:設置JVM最大可用堆內存。
-Xms3550m:設置JVM初始堆內存為3550m。此值可以設置與-Xmx相同,以避免每次垃圾回收完成后JVM重新分配內存
-Xmn2g:設置年輕代大小為2G。整個堆大小=年輕代大小+年老代大小+持久代大小。持久代一般固定在64m,所以增大年輕代后,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置整個堆的3/8
-Xss128k:設置每個線程的堆棧大小。JDK5以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256k。具應用的線程所需內存大小進行調整。在相同的物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,閥值在3000-5000左右。

java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermmSize=16m -XX:MaxTenuringThreshold=0

-XX:NewRatio=4:設置年輕代(包括Eden和兩個Survivor區(qū))與年老代的比值(除去持久劉代)。設置為4,則年輕代與年老代所占比值為1:4,年輕代占整個堆棧的1/5。
-XX:SurvivorRatio=4:設置年輕代中Eden區(qū)與Survivor區(qū)的大小比值。設置為4,則兩個Survivor區(qū)與一個Eden區(qū)的比值為2:4,一個Survivor?區(qū)占整個年輕代的1/6。
-XX:MaxPermSize=16m:設置持久代大小為16m。
-XX:MaxTenuringThreshold=0:設置垃圾最大年齡。如果設置為0的話,則年輕代對象不經過Survivor區(qū),直接進入老年代。對于年老代比較多的應用,可以提高效率。如果將此值設為一個較大值,則年輕對象會在Survivor區(qū)進行多次復制,這樣可以增加對象在年輕代的存活時間,增加年輕代即被回收的概論。

回收器選擇

JVM給了三種選擇:串行收集器、并行收集器、并發(fā)收集器,但是串行收集器只適用于小數據量的情況,所以這里的選擇主要針對并行收集器和并發(fā)收集器。默認情況下,JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在啟動時加入相應參數,JDK5.0以后,JVM會根據當前系統配置進行判斷

吞吐量優(yōu)先的并行收集器

如上文所述,并行收集器主要以到達一定的吞吐量為目標,適用于科學技術和后臺處理等。
典型配置:

java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParalelGC -XX:ParallelGCThreads=20

-XX:+UseParallelGC:選擇垃圾收集器為并行收集器。此配置僅對年輕代有效。年輕代使用并行收集,而年老代仍舊使用串行收集。
-XX:ParallelGCThreads=20:配置并行收集器的線程數,即:同時多少個線程一起進行垃圾回收。此值最好配置與處理器數目相等

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParalleloldGC

-XX:+UseParallelOldGC:配置年老代垃圾收集方式為并行收集:JDK6.0支持對年老代并行收集。

java-Xmx3550m-Xms3550m-Xmn2g-Xss128k-XX:+UseParallelGC -XX:MaxGCPauseMilis=100

-XX:MaxGCPauseMilis=100:設置每次年輕代垃圾回收的最長時間,如果無法滿足此時間,JVM會自動調整大小,以滿足此值

java -Xmx 3550m -Xms 3550m -Xmn2g -Xss128k -XX:+UseParalleGC -XX:MaxGCPauseMilis=100 -XX:+UseAdaptiveSizePolicy

-XX:+UseParalleGC:設置此項后,并行收集器會自動選擇年輕代區(qū)大小和相應的Surivor區(qū)比例,已達到目標系統規(guī)定的最低相應時間或者收集頻率等,此值建議使用并行收集器,一直打開。

響應時間優(yōu)先的并發(fā)收集器

如上文所述,并發(fā)收集器主要保證系統的響應時間,減少垃圾收集時間的停頓時間。適用于應用服務器、電信領域等。
典型配置:

java-Xmx3550m-Xms3550m-Xmn2g-Xss128k-XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC

-XX:+UseConcMarkSweepGC:設置年老代為并發(fā)收集。測試中配置這個以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此時年輕代大小最好用-Xmn設置。
XX:+UseParNewGC:設置年輕代為并行收集,可與CMS收集同時使用JDK5.0以上JVM會根據系統配置自行設置,所以無需再設置此值。

java-Xmx3550m-Xms3550m-Xmn2g-Xss128k-XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection

-XX:CMSFulGCsBeforeCompaction:由于并發(fā)收集器不對內存空間進行壓縮、整理,所以運行一段時間以后會產生“碎片”,使得運行效率降低。此值設置運行多少次GC以后對內存空間進行壓縮、整理
-XX:CMSCompactAtFullCollection:打開對年老代的壓縮。可能會影響性能,但是可以消除碎片

七、調優(yōu)總結 年輕代大小選擇

響應時間優(yōu)先的應用:盡可能設大,直到接近系統的最低響應時間限制(根據實際情況選擇);在此種情況下,年輕代收集發(fā)生的頻率也是最小的。同時,減少到達年老代的對象
吞吐量優(yōu)先的應用:盡可能的設置大,可能到達Gbit的程度。因為對響應時間沒有要求,垃圾收集可以并行進行,一般適合8CPU以上的應用。

年老代大小選擇

響應時間優(yōu)先的應用:年老代使用并發(fā)收集器,所以其大小需要小心設置,一般要考慮并發(fā)會話率和會話持續(xù)時間等一些參數。如果堆設置小了,可以會造成內存碎片、高回收頻率以及應用暫停而使用傳統的標記清除方式:如果堆大了,則需要較長的收集時間。最優(yōu)化的方案,一般需要參考以下數據獲得:

并發(fā)垃圾收集信息

持久代并發(fā)收集次數

傳統GC信息

花在年輕代和年老代回收上的時間比例減少年輕代和年老代花費的時間,一般會提高應用的效率

吞吐量優(yōu)先的應用:一般吞吐量優(yōu)先的應用都有一個很大的年輕代和一個較小的年老代。原因是,這樣可以盡可能回收掉大部分短期對象,減少中期的對象,而年老代盡存放長期存活對象。

較小堆引起的碎片問題

因為年老代的并發(fā)收集器使用標記、清除算法,所以不會對堆進行壓縮。當收集器回收時,他會把相鄰的空間進行合并,這樣可以分配給較大的對象。但是,當堆空間較小時,運行一段時間以后,就會出現“碎片”,如果并發(fā)收集器找不到足夠的空間,那么并發(fā)收集器將會停止,然后使用傳統的標記、清除方式進行回收。如果出現“碎片”,可能需要進行如下配置:
-XX:+UseCMSCompactAtFullCollection:使用并發(fā)收集器時,開啟對年老代的壓縮。
-XX:CMSFullGCsBeforeCompaction=0:上面配置開啟的情況下,這里設置多少次Full?GC后,對年老代進行壓縮。

八、常見異常

內存泄漏檢查
內存泄漏一般可以理解為系統資源(各方面的資源,堆、棧、線程等)在錯誤使用的情況下,導致使用完畢的資源無法回收(或沒有回收),從而導致新的資源分配請求無法完成,引起系統錯誤。內存泄漏對系統危害比較大,因為他可以直接導致系統的崩潰。需要區(qū)別一下,內存泄漏和系統超負荷兩者是有區(qū)別的,雖然可能導致的最終果是一樣的。內存泄漏是用完的資源沒有回收引起錯誤,而系統超負荷則是系統確實沒有那么多資源可以分配了(其他的資源都在使用)。

年老代堆空間被占滿
異常:java.lang.OutOfMemoryError.Java heap?space
說明:堆大小與使用堆成鋸齒狀。這是最典型的內存泄漏方式,簡單說就是所有堆空間都被無法回收的垃圾對象占滿,虛擬機無法再在分配新空間。鋸齒狀每一次形成三角的頂點而下降為回收點,所有谷底部分表示是一次垃圾回收后剩余的內存。連接所有谷底的點,可以發(fā)現一條由底到高的線,這說明,隨時間的推移,系統的堆空間被不斷占滿,最終會占滿整個堆空間。因此可以初步認為系統內部可能有內存泄漏。(上面的圖僅供示例,在實際情況下收集數據的時間需要更長,比如幾個小時或者幾天)
解決:通過jmap把可用對象打出來,這種方式解決起來也比較容易,一般就是根據垃極回收前后情況對比,同時根據對象引用情況(常見的集合對象引用)分析,基本都可以找到泄漏點。

持久代被占滿
異常:java.lang.OutOfMemoryError:PermGen?space
說明:Perm空間被占滿。無法為新的cdass分配存儲空間而引發(fā)的異常。這個異常以前是沒有的,但是在Java反射大量使用的今天這個異常比較常見了。主要原因就是大量動態(tài)反射生成的類不斷被加載,最終導致Perm區(qū)被占滿。
更可怕的是,不同的classLoader即便使用了相同的類,但是都會對其進行加載,相當于同一個東西,如果有N個classLoader那么他將會被加載N次。因此,某些情況下,這個問題基本視為無解。當然,存在大量classLoader和大量反射類的情況其實也不多。
解決:1.-XX:MaxPermSize=16m。2.換用JDK。比如JRocket。

堆棧溢出
異常:java.lang.StackOverflowError
說明:一般就是遞歸沒返回,或者循環(huán)調用造成.

線程堆棧滿
異常:Fatal:Stack size too small
說明:java中一個線程的空間大小是有限制的。JDK5.0以后這個值是1M。與這個線程相關的數據會保存在其中。但是當線程空間滿了以后,將會出現上面異常。
解決:增加線程棧大小。-Xss2m。但這個配置無法解決根本問題,還要看代碼部分是否有造成泄漏的部分。

系統內存被占滿
異常:java.lang.OutOfMemoryError:unable?to?create?new.native?thread
說明:
這個異常是由于操作系統沒有足夠的資源來產生這個線程造成的。系統創(chuàng)建線程時,除了要在Java堆中分配內存外,操作系統本身也需要分配資源來創(chuàng)建線程。因此,當線程數量大到一定程度以后,堆中或許還有空間,但是操作系統分配不出資源來了,就出現這個異常了。
分配給Java虛擬機的內存越多,系統剩余的資源就越少,因此,當系統內存固定時,分配給Java虛擬機的內存越多,那么,系統總共能夠產生的線程也就越少,兩者成反比的關系。同時,可以通過修改-Xss來減少分配給單個線程的空間,也可以增加系統總共內生產的線程數。
解決:1.重新設計系統減少線程數量。2.線程數量不能減少的情況下,通過-Xss減小單個線程大小。以便能生產更多的線程。

九、JVM調優(yōu)工具

JVM可視化監(jiān)控工具
Jconsole:jdk自帶,功能簡單,但是可以在系統有一定負荷的的情況下使用。對垃圾回收算法有很詳細的跟蹤。
Jprofile:商業(yè)軟件,需要付費。功能強大。
VisualVM:JDK自帶,功能強大,與JProfile類似。推薦。

JVM調優(yōu)監(jiān)控工具
jstat(性能分析)
https://www.jianshu.com/p/213710fb9e40

jstack(分析線程情況)
https://jingyan.baidu.com/article/4f34706e3ec075e387b56df2.html
http://www.importnew.com/23601.html

jmap(堆棧dump)
https://www.cnblogs.com/kongzhongqijing/articles/3621163.html

jinfo(jvm信息情況)
https://www.jianshu.com/p/ece32dacce64

jps(jvm進程情況)
https://www.jianshu.com/p/d39b2e208e72

JVM調優(yōu)工具轉載至一些優(yōu)質的博客,可以詳細學習參考

文檔整理于JVM視頻學習課程,感謝提供教育視頻的IT人才們,整理分享還未接觸到這層知識的人們,也收藏個人學習。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/74161.html

相關文章

  • Java性能調優(yōu)概述

    摘要:性能調優(yōu)概述性能優(yōu)化有風險和弊端,性能調優(yōu)必須有明確的目標,不要為了調優(yōu)而調優(yōu)盲目調優(yōu),風險遠大于收益程序性能的主要表現點執(zhí)行速度程序的反映是否迅速,響應時間是否足夠短內存分配內存分配是否合理,是否過多地消耗內存或者存在內存泄漏啟動時間程序 [TOC] Java性能調優(yōu)概述 性能優(yōu)化有風險和弊端,性能調優(yōu)必須有明確的目標,不要為了調優(yōu)而調優(yōu)!!!盲目調優(yōu),風險遠大于收益!!! 程序性...

    ad6623 評論0 收藏0
  • 近期Java高級工程師面試總結

    摘要:面試總結最近兩周面試了幾家公司高級工程師的職位,主要有宜信網信金融阿里高德口袋購物。目前有部分公司已經面試通過,兩家在等消息。今天趁熱把常見面試內容總結一下。可以用來完成統一命名服務狀態(tài)同步服務集群管理分布式應用配置項等管理工作。 面試總結 最近兩周面試了幾家公司Java高級工程師的職位,主要有宜信、網信金融、阿里高德、口袋購物。目前有部分公司已經面試通過,兩家在等消息。今天趁熱把常見...

    raoyi 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<