JVM堆內存監測的一種方式,性能調優依舊任重道遠

why830702 8年前發布 | 9K 次閱讀 JVM Java開發

JVM堆內存及一種監測方式

在討論Martijn的團隊如何進行堆內存監測之前,我們先回顧下JVM的工作機制。JVM是一種對計算機的抽象行為,是它保證了Java程序的運行。每一個運行的Java程序都對應著一個JVM實例。JVM的結構如下圖

Java把內存劃分成兩種:一種是棧內存,一種是堆內存。棧與堆都是Java用來在RAM中存放數據的地方。與C++不同,Java自動管理棧和堆,程序員不能直接地設置棧或堆。堆內存用來存放由new創建的對象和數組。在堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理。即每一個Java應用都唯一對應一個JVM實例,每一個實例唯一對應一個堆。

自從Java1.3之后,Oracle出臺的JRE就包含了一個名為HotSpot的JVM,它將Java的對象按照世代管理并存放在堆的內存中,以期可以更好地管理堆內存中的對象,包括內存的分配以及回收。共劃分為三個世代:年輕代、老年代、永久代。永久代(Permanent Generation)則存放的是類的定義和相關元數據。但是在Java 8中該區域已經被移除。 

現有版本保留的兩個世代為年輕代(Young Generation)和老年代(Old Generation)。年輕代為創建的短期對象,失效之后很快會被垃圾回收。該區又被劃分為Eden和兩個Survivor區域。老年代存放的多數為存活時間較長的對象。其中堆的各個區之間的比例分配有默認值,但是可以通過參數指定。垃圾回收GC分為兩種Minor GC、Full GC;Minor GC發生頻繁,但是僅針對年輕代。

垃圾回收之后會對JVM造成一定影響,年老代的占用空間曲線如下圖:

上圖來自jClarity對堆的年老代占用空間監測圖, jClarity是一款Java的性能監測工具 ,由Martijn、另外兩位資深Java專家和一位機器學習工程師共同實現。Martijn分享了jClarity如何進行堆內存的監測他首先列舉了垃圾回收之后,通常情況下堆內存中的老年代(Tenured/Old Generation)的內存占用曲線,一般而言,會先后發生兩個陡然增加的高峰。

基于以上現象的信息, Martijn和他的團隊開展了他們的性能監測方案。Martijn他們采取的做法是先收集盡可能多的點,然后只保留老年代的數據,對垃圾回收造成的兩個脈沖式波峰進行了過濾,這時再對這些真正的數據點進行建模抽象,最后保留出了一條曲線。

這條曲線就是對監測的Java程序內存的變化趨勢,該曲線會以50Mb/小時的速率增長,據此推測出何時發生內存泄露。jClarity還有很多其他功能,相比于傳統的指標統計方式,Martijn稱團隊產品的特點在于:高級統計+機器學習。

Java和JVM面臨怎樣的困境?

Martijn還分享了他對Java現狀和JVM性能調優的擔憂和思考,他認為現在Java和JVM面臨下面五個問題:

  1. 程序只能寫一次,但是卻要在各種地方跑
    這意味著Java需要解決來自各方面的差異:
    CPU的差異——什么時候可以放入緩存中呢?什么時候可以被重新排序呢?
    文件系統的差異——不同操作系統對文件的符號鏈接有不同機制
    顯示設備的差異——硬件更新速度很快,幾乎無法追上
    原生庫支持的差異——很難存在所有的原生庫皆一致的情況
    操作系統線程管理的差異——線程的規劃方式很不相同
    此外,面對正在迅速發展AR、VR,Java缺少真正的GPU支持,這同樣是一個短板。
  2. 模型對存儲的強需求
    JVM太謹慎了,他總想做對的事情,但是為此不得不在性能上的妥協。鎖機制加強了正確性,但是在性能上付出了巨大的代價。
    鎖機制決定了Java序列化的工作區。因為Java對象序列化不僅保留一個對象的數據,而且遞歸保存對象引用的每個對象的數據。可以將整個對象層次寫入字節流中,可以保存在文件中或在網絡連接上傳遞。利用對象序列化可以進行對象的"深復制",即復制對象本身及引用的對象本身。序列化一個對象可能得到整個對象序列。結合利特爾法則(Little's law)和阿姆達爾定律(Amdahl’s law),這種方式影響到了并行存儲的性能。
  3. 垃圾回收機制下的擴展性
    JVM需要維護活的對象,這意味著:堆需要更大空間以存放更多的對象;垃圾回收機制需要花時間去辨認哪些是活的對象;在垃圾回收過程中需要耗費時間進行堆的維護。
    其次,Java中沒有值類型(value type 和reference type的區別),沒有結構體:這造成了大量低效能的對象創建。
  4. 容器和虛擬化的支持
    Java沒法獲取虛擬化數據。Java和JVM的思考模式是建立在物理裸機上的,信息缺失的情況下會進行一些錯誤選擇。并且,沒有對Docker等容器技術的直接支持,這是新時代的另一個短板。

關于Java和JVM性能調優的思考

除了上述的整體層面的挑戰之外,Java的性能本身又很難監測。必須結合其他的指標來間接把控:CPU,內存;接口/O,網絡I/O;虛擬化和容器化等。可是一旦獲得了這些指標,又帶來了大數據的問題。因為我們盲目地收集了過多的數據,這造成了巨大的性能損害,因為收集、傳輸、存儲每個過程都是一種消耗。

要記住目的是分析獲得信息,而不是收集指標。但是從指標數據到提煉出有用信息很難,Martijn認為要做好性能調優需要明白規律和原理(如上文所提及的Little's law和Amdahl’s law),理解硬件、操作系統、Java工作原理還要讀懂代碼,并且已經有了基于大量數據的分析經驗。

Martijn認為未來性能監測的趨勢是高級統計和機器學習方式的結合,這種模式將取代傳統的單純指標采集模式。

對話Martijn

InfoQ:通常來說,JVM層面的APM工具并不適用于生產環境。那為什么您稱jClarity可以?

Martijn:與其他工具相比,首先在JVM層面上我們獲取更少的數據。 jClarity之所以可以更少地獲取,是因為我們采用了機器學習的辦法,辨別除了哪些才是真正有用的數據,我們稱之為“信號”,余下的數據我們稱之為噪聲。在收集數據過程中,一旦檢測噪聲,我們立刻對過濾。

其次我們還會盡可能避免從JVM本身獲取數據,取而代之從JVM的日志中(如GC日志、safepoint日志)等獲取數據。目前我們還在和Google合作,在嘗試怎樣從JVM之外,獲得更多的信息。但是,總體而言,jClarity用于生產環境是沒有問題的。

InfoQ:為什么還要收集JMV的日志之外的數據呢?

Martijn:因為JVM日志并不能給我們足夠的信息。你可以從JVM日志中獲得,或者通過JMX接口。不過,你也可以通過設定一個Java或者原生的agent來獲得更特定的信息;但這是一種過重的做法,通常而言并不推薦。很多人包括Oracle在內都意識到了這個問題,但是完全解決有待時日。

InfoQ:數據收集的過程是否對用戶來說是透明的呢?是否支持ASM字節碼織入技術呢?

Martijn:是的。底層的數據,我們不僅僅從Java中獲得,還會從操作系統中獲取。比如,當用戶在Linux上運行,那么他還會看見收集到的CPU、內存使用率等信息。

對于有特殊需求的用戶,他們是可以采用ASM,此外我們也提供一個開發階段使用的庫,但是建議用戶小心使用,因為很容易會產生操作不當。

InfoQ:數據收集之后,jClarity根據機器學習出來的成果進行了處理,能否和我們分享下機器學習的事情?

Martijn:在我被許可的范圍內,因為機器學習是我們的機密模塊。不過我可以分享這里非常重要的一點:我們有大量多環境的用戶數據,用戶們的程序也是多種多樣,如網頁程序、視頻流程序等;我們會施加不同的網絡壓力,這樣我們得到了數據訓練集。這些數據集是專家人工操作產生的。同時在實時收集處理數據的時候,我們也會進行機器學習。比如發現Java性能受到影響,機器學習認定最重要一個因素就是GC垃圾回收,那么接下來就是調查GC;如果GC沒有問題,那么就會在機器學習成果的指引下開始下一個因素的勘察。總體而言,機器學習的決定了發生問題時排查的路徑。

機器學習這部分的研發工作我們做了兩年,也很感謝這些用戶為我們付費并且同意我們這樣做。我們的一些用戶擁有超大規模,這種情況下,已經無法指望人工對數據進行分析;所以對于我們來說,機器學習是唯一的出路,唯一的方式可以讓我們繼續支持用戶。

InfoQ:APM工具的挑戰有哪些?

Martijn:首先是IT環境復雜性的加劇。你的代碼不再跑在你自己的機器和環境中,你無法做到100%確定你的程序和代碼是怎樣被管理的。另外一個挑戰就是網絡是不穩定的。在有線光纖專用網絡上,你不需要和其他人共享;但是在公用云上,網路流量徒增的情況時有發生,開發人員不得不在代碼層面上面對這個挑戰,APM工具也必須理解并迎面這個問題。目前,還沒有哪個APM工具可以勝任這兩個挑戰,所以目前這還是一個非常有趣有待研究的領域。

InfoQ:您在演講中有提到,Java創立之初硬件并沒有今天這樣復雜,那么是不是說Java已經不再適合今天了呢?你認為Java語言的獨特魅力在哪里呢?

Martijn:“Java將死”的留言每年都有。Java語言這么多年,經常遇到新興語言的挑戰,但是新興語言很快就會發現自己也處于一個類似的局面。我認為Java依然是一個合適的語言,JVM正在嘗試在各種情況下都做到最好。我們可以看到Go、RUST語言變得越來越火,但是Oracle正在非常努力地攻克這點,包括更頻繁地發布Java,也很想快速地跟上包括支持GPU、其他新型硬件設備等。所以說挑戰是有的,但是令人高興的是很多大公司都愿意繼續努力提高Java。我希望Java社區可以更開放些,可以歡迎更多的公司參與,比如阿里巴巴,阿里巴巴可能是全球上最大的重度Java研發群。

Java的魅力在于易寫性、強可讀性。不像現在的一些語言,你不需要嚴格地按照某種規范來寫代碼。就算代碼寫完五年之后,新來的人依然可以讀懂代碼。還有就是Java豐富的框架和庫。甚至這些框架和庫的魅力可以和Java語言本身相媲美。

 

 

來自:http://www.infoq.com/cn/news/2016/09/APM-jClarity-jvm-heap-oldgen

 

 本文由用戶 why830702 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!