對(duì)于容器應(yīng)用程序來說,很難發(fā)現(xiàn)內(nèi)存過度使用導(dǎo)致的問題。如果使用超過了容器內(nèi)存限制,應(yīng)用程序可能會(huì)悄無聲息地失敗而不會(huì)留下任何痕跡。
在本文中,我將介紹一些可用于識(shí)別Java容器應(yīng)用程序中內(nèi)存消耗來源的技術(shù)。
內(nèi)存類型
在典型的Java應(yīng)用程序中,內(nèi)存可以大致分為堆和非堆。堆內(nèi)存可以通過在啟動(dòng)任何Java應(yīng)用程序時(shí)提供相關(guān)的JVM參數(shù)來設(shè)置。
非堆內(nèi)存由JVM本身使用的本機(jī)內(nèi)存或任何使用JNI (Java本機(jī)接口)的應(yīng)用程序中使用的庫組成。
方法
對(duì)于堆內(nèi)存,可以使用堆轉(zhuǎn)儲(chǔ)分析工具獲取和分析堆轉(zhuǎn)儲(chǔ)。用于堆轉(zhuǎn)儲(chǔ)分析的最佳工具之一是eclipseMAT。
Java通過啟用本機(jī)內(nèi)存跟蹤提供了一種跟蹤本機(jī)內(nèi)存分配的機(jī)制,但它可能不會(huì)顯示本機(jī)庫分配的所有內(nèi)存。
Jemalloc是一個(gè)實(shí)用程序,可用于跟蹤本地庫分配的內(nèi)存。使用名為malloc的默認(rèn)內(nèi)存分配器來分配本機(jī)內(nèi)存。Jemalloc是一種通用的malloc實(shí)現(xiàn),使用它可以啟用內(nèi)存分配跟蹤。它跟蹤所有本機(jī)內(nèi)存分配并生成堆配置文件轉(zhuǎn)儲(chǔ)。
然后可以使用Jeprof實(shí)用程序來分析這些堆配置文件。Jeprof生成堆分配報(bào)告,突出顯示應(yīng)用程序中函數(shù)使用的內(nèi)存。
分析
下面是一個(gè)示例容器Java應(yīng)用程序的內(nèi)存分析。該應(yīng)用程序加載一個(gè)示例Tensorflow模型以實(shí)現(xiàn)本機(jī)內(nèi)存利用率,并在Docker容器中運(yùn)行。
以下是Docker內(nèi)存消耗情況,它顯示254MB。讓我們?cè)囍页鰞?nèi)存消耗的來源。
總內(nèi)存
為了了解應(yīng)用程序進(jìn)程正在使用的總內(nèi)存,我們可以檢查常駐集大小(RSS)。它是駐留在主內(nèi)存或RAM中的總提交內(nèi)存。有多個(gè)實(shí)用程序可以幫助檢查這一點(diǎn),如top、ps或pmap。
檢查RSS無助于確定使用的根本來源。對(duì)于示例應(yīng)用程序,使用以下命令,總RSS為376MB。
堆積分析
下面是eclipse MAT工具生成的堆內(nèi)存消耗。總保留堆顯示為2.2MB,遠(yuǎn)低于Docker顯示的總內(nèi)存消耗,表明大部分消耗來自非堆區(qū)域。
本地內(nèi)存分析
使用以下命令查看本機(jī)內(nèi)存摘要時(shí),總內(nèi)存使用量似乎約為99MB。但是,該值小于總內(nèi)存消耗,不能準(zhǔn)確識(shí)別問題的根本原因。
堆外內(nèi)存分析
使用Jemalloc和Jeprof進(jìn)行的分析顯示,本機(jī)內(nèi)存使用主要?dú)w因于Tensorflow庫,總消耗約為112MB。
這種見解清楚地表明了本機(jī)內(nèi)存使用的來源,可以進(jìn)一步調(diào)查以最大限度地減少任何過度消耗。
結(jié)論
Java內(nèi)存分析至關(guān)重要,尤其是對(duì)于基于容器的應(yīng)用程序。了解應(yīng)用程序中內(nèi)存消耗的來源可以幫助我們了解內(nèi)存需求,并通過消除不必要的消耗來降低應(yīng)用程序成本。
檢查內(nèi)存消耗時(shí),需要查明所有類型的內(nèi)存及其來源。堆轉(zhuǎn)儲(chǔ)分析可以查明堆內(nèi)存消耗源,Jemalloc和Jeprof在查明本機(jī)內(nèi)存消耗源方面非常有用。