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

資訊專欄INFORMATION COLUMN

jvm內存分配策略和性能監控

Baoyuan / 535人閱讀

摘要:概述本篇旨在講清楚的內存分配策略,日志閱讀,一些常見名詞和提供的一些性能監控工具。內存分配與回收策略對象優先在分配大多數情況下,對象優先在新生代區中分配。當區域沒有足夠空間進行分配時,將發生一次。

概述

本篇旨在講清楚jvm的內存分配策略,gc日志閱讀,一些常見名詞和jdk提供的一些性能監控工具。廢話不多說,開始上貨。

GC日志閱讀

在開發的世界里,閱讀日志是最基礎的能力,也是解決問題重要的工具。同樣閱讀gc日志也是解決虛擬機內存的基礎技能,通過配置參數-XX:+PrintGCDetails就可以打印gc日志,建議加上參數-Xloggc指定gc日志目錄,避免gc日志和console控制臺日志混亂造成的閱讀困難。
每一種收集器的日志都會略有不同,但會維持一定的共性,以下面一段日志為例:

0.332: [GC (Allocation Failure) [PSYoungGen: 6120K->504K(6144K)] 12535K->12549K(19968K), 0.0066909 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
0.339: [Full GC (Ergonomics) [PSYoungGen: 504K->0K(6144K)] [ParOldGen: 12045K->10615K(13824K)] 12549K->10615K(19968K), [Metaspace: 3473K->3473K(1056768K)], 0.1372999 secs] [Times: user=0.28 sys=0.00, real=0.14 secs] 

最前面的0.332和0.339代表了gc的發生的時間,它的含義是表達虛擬機啟動到發生gc的秒數。后面的GC和Full GC代表著垃圾收集的停頓類型,如果是GC代表的是新生代的GC,也稱ygc和minor gc,fullgc代表的是對整堆的一個gc。后面括號里的Allocation Failure和Ergonomics代表的是發生gc的原因,分別是eden區域空間不夠和parOldGen空間不夠導致的gc和fullgc問題。以Full GC為例,接下來的[PSYoungGen、[ParOldGen、[Metaspace代表gc發生的區域,分別是年輕代、老年代、元空間,其名字也是由所使用的gc收集器密切相關,大致如下:

收集器                    顯示區域
serial                   DefNew
ParNew                   ParNew
Parallel Scavenge        PSYoungGen
serial old               Tenured
parallel old             ParOldGen
CMS                      CMS

后面方括號內部的 504K->0K(6144K)代表著該區域GC前使用容量-》GC后該區域所使用容量(該區域總容量),方括號之外的12549K->10615K(19968K)則代表gc之前堆中使用容量-》gc后堆中使用容量(堆總容量)。0.1372999 secs這個很簡單,代表gc占用時間,單位是秒。

內存分配與回收策略

對象優先在Eden分配
大多數情況下,對象優先在新生代Eden區中分配。當Eden區域沒有足夠空間進行分配時,將發生一次Minor GC。虛擬機提供了-XX:+PrintGCDetails用來輸出gc日志,此日志會告訴我們垃圾收集行為時的內存日志,并在進程結束后輸出當前內存各區域的分配情況。上例子:

public class TestAllocation {

    private static final int _1MB=1024*1024;

    public static void main(String[] args) {
        byte[] a1,a2,a3,a4;
        a1=new byte[2*_1MB];
        a2=new byte[2*_1MB];
        a3=new byte[2*_1MB];
        a4=new byte[4*_1MB];
    }
}

gc日志如下所示:

"C:Program FilesJavajdk1.8.0_151injava" -XX:+PrintGCDetails -Xmx20m -Xms20m -Xmn10m 
[GC (Allocation Failure) [PSYoungGen: 6294K->808K(9216K)] 6294K->4912K(19456K), 0.0023349 secs] [Times: user=0.09 sys=0.00, real=0.02 secs] 
Heap
 PSYoungGen      total 9216K, used 7273K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 78% used [0x00000000ff600000,0x00000000ffc50670,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 4104K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff600000)
 Metaspace       used 3473K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 381K, capacity 388K, committed 512K, reserved 1048576K

其中vm配置參數從第一行便可知。新生代分為eden區域和兩塊survior區域,默認比例為8:1:1,從圖中eden:from:to=8192:1024:1024可以得到驗證。下來我們就根據gc日志分析下在執行這段程序時,jvm究竟都做了哪些事。

從這張圖片可知,在jdk1.8.0_151中,即使跑一個空的main函數,新生代就要占2362k,這個是虛擬機的初始內存占用,好奇寶寶可以通過jmap命令看看到底堆里裝了什么。現在讓我們回到最開始代碼中,會將a1、a2分配在新生代的eden區,此時eden區域為2048k+2048K+2362k=6458k,因為eden區域空間不夠,不足以將a3裝入,此時觸發minor gc,又因為此時a1、a2對象還存活,suivor區域只有1024k,故將a1、a2分配擔保到老年代。從日志中可知,經歷過一次minor gc新生代還有808k的存活對象,因為a1、a2已經擔保到老年代,故這是初始內存中經過gc存活的對象,通過復制算法轉移到survivor中。此時eden區域是0k,其中一塊survivor是初始內存,老年代存放著a1、a2對象,此時開始繼續分配對象內存,因a3+a4

大對象直接進入老年代
哪怕你從來沒有學習過jvm知識,你或許也聽說過江湖上流傳著大對象直接進入老年代這個傳聞。很多人都知道這個知識點,但恐怕大多數人并不能準確的去描述這個分配策略。
1.何謂大對象?
所謂大對象就是需要大量連續內存空間的對象,上個例子中的byte數組就是典型的大對象。
2.參數-XX:PretenureSizeThreshold的作用?
虛擬機提供了-XX:PretenureSizeThreshold,令大于這個值得對象直接在老年代分配。hotspot可以在年輕代手機內存的收集器有Serial、ParNew、Parallel Scavenge以及G1(G1劃分內存區域比較特殊暫不考慮)。其中只有Serial和ParNew收集器可以識別這個參數,Parallel Scavenge是不識別這個參數的,但并不是大對象直接進入老年代分配策略對其就是無效的,在Parallel Scavenge中自有它的實現,大約等于Eden區域一半的對象會被認成大對象。感興趣的可以來這看看,傳送門:鏈接描述.如果想要使用-XX:PretenureSizeThreshold參數,可以考慮使用ParNew+CMS的組合。給大家展示一個例子:

    public class BigObject {

    public static void main(String[] args) {
        byte[] test = new byte[4*1024*1024];
    }
}


從gc日志,我們很容易得出大對象進入老年代這個結論。對了,還需要注意的是XX:PretenureSizeThreshold的單位是k,不能像-Xmx3mb這樣直接指定。
3.為什么大對象要進入老年代?
在搞清楚這個問題之前,我們首先要去揣摩大師們設計分代算法的意圖。設計師們希望新生代的對象多數是朝生夕滅的,故新生代采用復制算法最合適。復制算法的優點是簡單,速度快(在存活對象少的情況下),缺點是占內存要發生內存復制。這樣做的目的就是避免在eden區和兩個survivor區之間發生大量的內存復制。

長期存活的對象將進入老年代
虛擬機給每個對象定義了一個對象年齡計數器,保存在對象頭中的Mark word部分。如果對象在eden出生,經歷過一次minor gc仍然活著,并且能被survivor區容納,將會被移動到survivor區域,并且將gc年齡設置為1,這種對象沒經歷一次Minor gc ,年齡就增加一歲,當它的年齡增加到一定程度(默認是15歲),就會被晉升到老年代,這個年齡閾值可以通過參數-XX:MaxTenuringThresold來設置.

動態對象年齡判定
虛擬機并不是永遠要求對象的年齡永遠達到MaxTenuringThresold才能晉升老年代,如果在survivor空間中相同年齡所有的對象的大小總和大于survivor空間的一半,年齡大于或等于改年齡的對象直接進入老年代,無須等到MaxTenuringThresold要求的年齡。

空間分配擔保
在發生minor gc之間,虛擬機會先檢查老年代最大可用的連續空間是否大于新生代所有對象總空間,如果條件成立,則代表這次gc是安全的。如果不成立,jdk1.7和jdk1.8的版本中會繼續檢查老年代最大的可用空間是否大于歷次晉升到老年代對象的平均大小,如果小于則進行一次full gc,如果大于則嘗試進行一次minor gc,如果出現老年代擔保失敗的情況則會進行一次full gc。

性能監控與故障處理工具

給一個系統定位問題的時候,知識、經驗是關鍵基礎,數據是依據,工具是運用知識處理數據的手段。java開發程序員應該都知道jdk的bin目錄下有java.exe和javac.exe,但其實bin下面還有很多的小工具都極其實用,是我們排查問題的關鍵。工具很多,我們挑幾個最常用的來說明:

jstat

可以用來監視虛擬機各種運行時狀態信息的命令行工具。jstat格式命令為:

jstat [ option vmid [interval[s|ms] [count]] ]

option代表我們想要查詢的虛擬機信息,vmid就是我們的進程id,interval和count代表查詢間隔(默認單位是ms)和次數。jstat工具主要選項如下圖所示:

gccause是最常用的一個option之一,假如我們需要每250ms查詢一次進程5888的垃圾收集情況,一共查詢20次,命令應該為:

S0和S1對應的是新生代的兩塊suivor區域,E對應的是Eden,O對應的是老年代,M對應的是Klass Metaspace以及Noklass Metaspace兩者總共的使用率,CCS對應的是NoKlass Metaspace的使用率,YGC表示的是新生代gc發生的次數,YGCT表示的是新生代gc總共的stop the world的時間,FGC表示的是Full gc的次數,FGCT GCT同YGCT一樣就不多說了,LGCC表示上次gc的原因,GCC表示此次gc的原因。需要額外注意的是,當使用CMS作為老年代收集器的時候,每執行一次Old GC,FGC就會增加兩次。

jinfo

:可以用來實時查看和調整虛擬機的各項參數。
使用jps -v pid可以查看虛擬機啟動時顯示指定的參數,前提是你要開rmi。如果想要查看未被指定參數的默認值,除了查文檔就只能通過jinfo -flag 選項進行查詢,當然如果你使用java -XX:+PrintFlagsFinal查看默認值也是一個很好的選擇(此命令會打印出所有的默認值),同時你還可以通過jinfo -flag [+|-] name=value或者-flag name=value修改一部分運行期可寫的虛擬機參數,如果想要查看那些事運行期可寫的參數,可以通過命令java -XX:+PrintFlagsFinal |grep manageable查詢。

jmap

jmap命令主要用于生成堆轉儲快照,一般稱為dump文件。當然它的作用不僅僅只有這個,還有查詢java堆和方法區的詳細信息.生成dump文件。其使用方法如下:

生成堆轉儲快照: jmap -dump:format=b,file=gc.bin pid(線上慎用,如果堆文件較大,會比較耗時,因為要保證dump的準確性,會發生stop the world)
查看堆詳細信息,使用回收期、參數配置和分代狀況等:jmap -heap pid
查看對象統計信息:jmap -histo pid(如果加上參數:live,jmap -histo:live pid會率先執行一次gc,線上慎用)

jhat

jhat命令可與jmap搭配使用,用來分析dump文件,其內置了一個http服務器,生成分析結果,可以在瀏覽器查看。不過一般都不會用jhat來分析,原因有兩點1:不會直接在部署服務器上分析,因為分析工作是一個耗時且消耗硬件資源的過程。2:因為jhat分析確實比較簡陋,目前eclispe的mat是分析dump文件最專業的工具,可以到eclispe官網下載插件版,無須安裝eclispe。

jstack

jstack命令用于生成虛擬機當前時刻的線程快照,一般稱為threaddump或javacore文件。線程快照就是當前虛擬機內每一條線程正在執行的方法堆棧的集合,主要用來定位線程出現長時間停頓的原因,如線程間死鎖、死循環、請求外部資源長時間等待等都是導致線程長時間停頓的主要原因。

在jdk1.5中, Thread類新增了一個getAllStackTraces()方法用于獲取虛擬機中所有的StackTraceElement對象,使用這個方法可以完成jstack的大部分功能,可以在實際的項目中用這個方法做個管理頁面,來隨時監控線程堆棧。

VisualVM

VisualVmM是jdk發布到目前為止,最強大的運行監視和故障處理數據,他有一個很大的優點不需要被監視的程序基于特殊的agent運行,因此它對應用程序地實際性能影響很小,使得它可以直接應用到生產環境中。它上面有許多好玩的插件,比如Btrace,它可是線上調試的神奇,可以在不停止目標程序運行的前提下,通過hotspot的hotswap技術動態加入原本不存在的調試代碼。這個插件等以后有機會了再具體介紹下。

總結

基本上,hotspot系列jvm的理論知識和常用性能監控工具已經介紹完畢,但這些知識只是jvm世界的一點皮毛,如果大家想要學習更多的知識,可以去關注R大,被稱為jvm源碼化身的男人。傳送門:https://www.zhihu.com/people/...。另外阿里的你假笨同學開發了兩個特別實用的程序,微信小程序JVMPocket和網站:http://xxfox.perfma.com/,至于它們有什么功效,大家自己去體驗吧^_^。

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

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

相關文章

  • 聊聊企業級 Java 應用最重要的4個性能指標

    摘要:筆者多次參與銀行運營商等大型企業的性能優化工作總結了企業級應用最應重視的個性能指標,主要包括商業事務,外部服務,垃圾回收以及應用布局。應用布局最后要探討的性能指標是應用布局。另一個需要監測的是容器性能。 雖然很多人都曾預言 Java 將一蹶不振,但是不可否認的是,很多重要項目中,尤其是銀行和政府一些大型項目,Java 仍在其中扮演著極其重要的角色。筆者多次參與銀行、運營商等大型企業的性...

    sherlock221 評論0 收藏0
  • 系統優化怎么做-JVM優化之開篇

    摘要:幾個死鎖場景兩個線程相互調用導致互相等待同步結束。線程為了檢測死鎖,它需要遞進地檢測所有被請求的鎖。思考題線程有哪些狀態這些線程大多處于什么樣的狀態分布我們可以稱系統運行是健康的。 前言 在上一期Tomcat優化中,針對JVM相關主要參數做過一定說明,這一期主要介紹進行一些概念及經驗。后面分章節去講述相關工具的基本使用。 優化優先級 整體來講,系統優化應先優化架構及代碼,來解決具體功能...

    gecko23 評論0 收藏0
  • Android內存泄漏總結

    摘要:內存泄漏總結內存管理的目的就是讓我們在開發中怎么有效的避免我們的應用出現內存泄漏的問題。在中,內存泄漏的范圍更大一些。 Android 內存泄漏總結 內存管理的目的就是讓我們在開發中怎么有效的避免我們的應用出現內存泄漏的問題。內存泄漏大家都不陌生了,簡單粗俗的講,就是該被釋放的對象沒有釋放,一直被某個或某些實例所持有卻不再被使用導致 GC 不能回收。最近自己閱讀了大量相關的文檔資料,打...

    legendaryedu 評論0 收藏0
  • 內存泄露從入門到精通三部曲之基礎知識篇

    摘要:騰訊特約作者姚潮生首先以一個內存泄露實例來開始本節基礎概念的內容。堆內存用于存放所有由創建的對象內容包括該對象其中的所有成員變量和數組。回到我們的問題,為什么內存會泄露堆內存中的長生命周期的對象持有短生命周期對象的強軟引用,盡管 騰訊Bugly特約作者: 姚潮生 首先以一個內存泄露實例來開始本節基礎概念的內容。 實例1:單例導致內存對象無法釋放而泄露 showImg(http://i....

    nicercode 評論0 收藏0
  • [譯]GC專家系列5-Java應用性能優化的原則

    摘要:在本文中我將會介紹應用性能優化的一般原則。性能優化的流程圖摘取自和合著的性能,描述了應用性能優化的處理流程。例如,對每臺服務器,你面臨著為單個分配堆內存和運行個并為每個分配堆內存的選擇。不過位能使用堆內存最大理論值只有。 原文鏈接:http://www.cubrid.org/blog/dev-platform/the-principles-of-java-application-per...

    lufficc 評論0 收藏0

發表評論

0條評論

Baoyuan

|高級講師

TA的文章

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