容器中Java RAM的使用:不会丢失内存的5大技巧
在本文中,我們希望分享Java內存管理的細節和容器內部的彈性,這些細節乍一看并不明顯。
在下面,您將找到要注意的問題列表以及即將發布的JDK版本中的重要更新,以及針對核心痛點的現有解決方法。 我們收集了5個最有趣,最有用的技巧,以提高Java應用程序的資源使用效率。
Docker中的Java堆內存限制
當前,社區正在討論有關在Docker容器中運行Java應用程序時錯誤地確定內存限制的問題。
問題是,如果未明確定義Xmx選項,則由于默認的內部垃圾回收(GC)人機工程學算法,JVM使用了可用于主機OS的所有內存的1/4。 如果JVM內存使用量超過為Docker容器定義的cgroups限制,則可能導致內核殺死Java進程。
為了解決此問題,OpenJDK 9最近實現了一項改進:
OpenJDK 9已添加了第一個實驗性更改,因此JVM可以了解它正在容器中運行并相應地調整內存限制。” 如果使用Docker運行Java 9發行版將調整內存限制
新的JVM選項( -XX:+ UseCGroupMemoryLimitForHeap )根據cgroup中定義的內存限制自動為Java進程設置Xmx。
作為解決公共Java 9發行前問題的一個不錯的解決方法,可以在JVM的啟動選項中顯式指定Xmx限制。 OpenJDK官方倉庫中有一個公開拉取請求,要求“根據docker內存限制設置一個更好的默認Xmx值的腳本”。
Jelastic設法通過結合使用增強的系統容器虛擬化層和Docker映像來省略錯誤的內存限制確定。 在前面的文章“容器中的Java和內存限制:LXC,Docker和OpenVZ”中,我們解釋了它的工作原理。
跟蹤本機非堆內存使用情況
在云中運行Java應用程序時,還必須注意Java進程對本機內存的使用,即所謂的堆外內存。 它可以用于不同目的:
- 垃圾收集器和JIT優化正在跟蹤對象圖的數據并將其存儲在本機內存中。 此外,自JDK8起,類的名稱和字段,方法的字節碼,常量池等現在位于Metaspace中,該空間也存儲在JVM堆之外。
- 另外,為了獲得高性能,許多Java應用程序在本機區域分配內存。 使用java.nio.ByteBuffer或第三方JNI庫,這些應用程序存儲大型的,長壽命的緩沖區,這些緩沖區由基礎系統的本機I / O操作管理。
默認情況下,元空間分配僅受可用本機OS內存量的限制。 再加上Docker容器中錯誤的內存限制確定,這增加了應用程序不穩定的風險。 限制元數據的大小很重要,尤其是在遇到OOM問題時。 使用特殊選項-XX:MetaspaceSize來執行此操作 。
由于所有對象都存儲在正常的垃圾回收堆內存之外,因此,它們對Java應用程序的內存占用量有什么影響并不明顯。 有一篇很好的文章詳細解釋了該問題,并提供了一些有關如何分析本機內存使用情況的準則:
“幾周前,我在嘗試分析在Docker下運行的Java應用程序(Spring Boot + Infinispan)中的內存消耗時遇到了一個有趣的問題。 Xmx參數設置為256m,但是Docker監視工具顯示的已用內存幾乎增加了兩倍。” – 分析Docker容器中的Java內存使用情況 。
作者的有趣結論:
“我可以說一個結論嗎? 好吧……永遠不要在我開玩笑的同一句話中使用“ java”和“ micro”這兩個詞–請記住,在使用Java,Linux和Docker的情況下處理內存比起初看起來要棘手得多。”
為了跟蹤本機內存分配,可以使用特定的JVM選項( -XX:NativeMemoryTracking = summary )。 請注意,如果啟用此選項,您將獲得5-10%的效果。
在運行時調整JVM內存使用量
減少Java應用程序內存消耗的另一個有用的解決方案是在Java進程運行時動態調整JVM可管理選項。 由于JDK7u60和JDK8u20,選項MinHeapFreeRatio和MaxHeapFreeRatio成為可管理的,這意味著我們可以改變在運行時它們的值,而無需重新啟動Java進程。
在“ 運行時承諾的堆大小調整”一文中,作者描述了如何通過調整以下可管理選項來減少內存使用:
“…調整大小又花了一個時間,并且堆容量從159MB增加到444MB。 我們描述了至少85%的堆容量應該是可用的,并且這表明JVM調整了堆的大小以獲取最多15%的使用率。”
這種方法可以為可變工作負載帶來顯著的資源使用優化。 改善JVM內存大小的下一步是可以在運行時模式下更改Xmx,而無需重新啟動Java進程。
改善內存壓縮
在許多情況下,客戶希望最大程度地減少Java應用程序中使用的內存量,從而導致產生更頻繁的GC。 例如,它可以通過在開發,測試和構建環境以及負載高峰后的生產中更有效地利用資源來幫助節省資金。 但是,根據官方的增強票證 ,當前的GC算法需要多個完整的垃圾回收周期才能釋放所有可用的未使用內存。
結果,引入了新的JVM選項( -XX:+ ShrinkHeapInSteps )來調節JDK9中的GC算法行為。 該設置應更改為-XX:-ShrinkHeapInSteps,以禁用4個完整的GC周期。 這樣可以更快地釋放未使用的RAM資源,并最大程度地減少負載可變的應用程序中Java堆大小的使用。
減少內存使用以加快實時遷移
占用大量內存的Java應用程序的實時遷移需要大量時間。 為了減少總遷移時間和資源開銷,遷移引擎應盡量減少主機之間傳輸的數據。 這可以通過在實時遷移過程之前借助整個GC周期壓縮RAM來完成。 對于克服GC周期期間性能下降的情況,這種方法對于各種應用程序而言,與使用未打包的RAM進行遷移相比可能更具成本效益。
我們發現了與該主題相關的出色研究工作: GC輔助Java Server Applications的JVM Live Migration 。 作者將JVM與CRIU(在用戶空間中的Checkpoint / Restore)集成在一起,并引入了一種新的GC邏輯,以減少Java應用程序從一臺主機實時遷移到另一臺主機的時間。 提供的方法允許在獲取Java進程狀態的快照之前啟用可感知遷移的垃圾收集,然后通過在磁盤上檢查點來凍結正在運行的容器,然后從凍結點恢復容器。
另外,Docker社區正在將CRIU集成到主流中。 目前,此功能仍處于試驗階段。
Java和CRIU的組合可以釋放仍未發現的性能和部署優化機會,以改善云中Java應用程序的托管。 您可以在“ 容器實時遷移:幕后 ”一文中找到有關容器實時遷移如何在云中工作的更多詳細信息。
Java很棒,并且已經在云中(特別是在容器中)很好地工作了,但是我們相信它會更好。 因此,在本文中,我們介紹了一系列當前問題,可以對這些問題進行改進,以平穩高效地運行Java應用程序。
在Jelastic,我們在全球數百個數據中心中運行著數千個Java容器。 良好的內存管理對我們至關重要。 這就是為什么我們不斷將有關Java內存的新發現納入我們的平臺的原因,因此開發人員不必明確處理這些問題。 嘗試在Jelastic增強平臺上運行Java容器 。
翻譯自: https://www.javacodegeeks.com/2017/04/java-ram-usage-containers-top-5-tips-not-lose-memory.html
總結
以上是生活随笔為你收集整理的容器中Java RAM的使用:不会丢失内存的5大技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 发票遗失备案流程(发票遗失备案)
- 下一篇: linux多核cpu调度(linux 多