对于容器应用程序来说,很难发现内存过度使用导致的问题。如果使用超过了容器内存限制,应用程序可能会悄无声息地失败而不会留下任何痕迹。
在本文中,我将介绍一些可用于识别Java容器应用程序中内存消耗来源的技术。
内存类型
在典型的Java应用程序中,内存可以大致分为堆和非堆。堆内存可以通过在启动任何Java应用程序时提供相关的JVM参数来设置。
非堆内存由JVM本身使用的本机内存或任何使用JNI (Java本机接口)的应用程序中使用的库组成。
方法
对于堆内存,可以使用堆转储分析工具获取和分析堆转储。用于堆转储分析的最佳工具之一是eclipseMAT。
Java通过启用本机内存跟踪提供了一种跟踪本机内存分配的机制,但它可能不会显示本机库分配的所有内存。
Jemalloc是一个实用程序,可用于跟踪本地库分配的内存。使用名为malloc的默认内存分配器来分配本机内存。Jemalloc是一种通用的malloc实现,使用它可以启用内存分配跟踪。它跟踪所有本机内存分配并生成堆配置文件转储。
然后可以使用Jeprof实用程序来分析这些堆配置文件。Jeprof生成堆分配报告,突出显示应用程序中函数使用的内存。
分析
下面是一个示例容器Java应用程序的内存分析。该应用程序加载一个示例Tensorflow模型以实现本机内存利用率,并在Docker容器中运行。
以下是Docker内存消耗情况,它显示254MB。让我们试着找出内存消耗的来源。
总内存
为了了解应用程序进程正在使用的总内存,我们可以检查常驻集大小(RSS)。它是驻留在主内存或RAM中的总提交内存。有多个实用程序可以帮助检查这一点,如top、ps或pmap。
检查RSS无助于确定使用的根本来源。对于示例应用程序,使用以下命令,总RSS为376MB。
堆积分析
下面是eclipse MAT工具生成的堆内存消耗。总保留堆显示为2.2MB,远低于Docker显示的总内存消耗,表明大部分消耗来自非堆区域。
本地内存分析
使用以下命令查看本机内存摘要时,总内存使用量似乎约为99MB。但是,该值小于总内存消耗,不能准确识别问题的根本原因。
堆外内存分析
使用Jemalloc和Jeprof进行的分析显示,本机内存使用主要归因于Tensorflow库,总消耗约为112MB。
这种见解清楚地表明了本机内存使用的来源,可以进一步调查以最大限度地减少任何过度消耗。
结论
Java内存分析至关重要,尤其是对于基于容器的应用程序。了解应用程序中内存消耗的来源可以帮助我们了解内存需求,并通过消除不必要的消耗来降低应用程序成本。
检查内存消耗时,需要查明所有类型的内存及其来源。堆转储分析可以查明堆内存消耗源,Jemalloc和Jeprof在查明本机内存消耗源方面非常有用。