内存全景分析功能适用于内存占用较高但无法明确识别具体内存占用情况的场景。通过使用内存全景分析诊断功能,可以扫描当前系统的内存占用状态,详细拆解内存使用情况。生成的报告将以饼状图的形式呈现系统内存与应用内存的分布,并列出当前Top 30的应用内存使用、文件缓存、共享内存缓存占用情况的排序。本文介绍了内存全景分析功能的使用说明。
使用限制
地域限制
本功能目前仅支持中国内地与中国香港。
操作系统限制
架构
操作系统
x86架构
Rocky Linux 9.5
Rocky Linux 9.1
Ubuntu 20.04
Alibaba Cloud Linux 3 容器优化版
Rocky Linux 8.8
Ubuntu 22.04
Alibaba Cloud Linux 3 Pro
Alibaba Cloud Linux 2/3
CentOS 7.6及更高版本,或CentOS 8
Anolis OS 7/8
Ubuntu 24.04
ARM架构
Alibaba Cloud Linux 3 Pro
Alibaba Cloud Linux 3
前提条件
如果您使用RAM用户,请确保阿里云账号(主账号)已将系统策略
AliyunECSReadOnlyAccess和AliyunSysomFullAccess授予RAM用户。已开通控制台权限。
首次登录操作系统控制台时,单击开通服务以开通控制台服务。
操作步骤
访问操作系统控制台。
在左侧导航栏,单击系统诊断。
在页面左侧顶部,选择目标实例所在的地域。

诊断实例整体状态
在诊断类型列表中,选择内存诊断;在诊断项列表中,选择内存全景分析;选择目标实例ID后,单击执行诊断。
说明若未安装SysOM,单击执行诊断后,系统将自动为目标ECS实例安装SysOM,并随之发起诊断。
诊断实例中的Java应用
在诊断模式中选择节点诊断,在诊断类型列表中,选择内存诊断。在诊断项列表中,选择内存全景分析。
选择Java进程所在目标实例ID;
选择打开或关闭应用内存profiling,打开后选择profiling时长,单位为分钟,不设置或设置为0则不进行profiling。
如果想对特定进程进行profiling,可以填写对应的pid;不填写默认对占用内存最大的Java进程进行profiling
单击执行诊断。
重要开启应用内存profiling需要先对实例或Pod所在实例进行纳管。
开启应用内存profiling有一定性能、内存开销,内存占用根据符号大小占用50 - 300MB。.
诊断Pod中的Java应用
在诊断模式中选择Pod诊断,选择集群类型,集群ID,在诊断类型列表中,选择内存诊断。在诊断项列表中,选择内存全景分析。
选择Java进程所在目标Pod。
选择打开或关闭应用内存profiling,打开后选择profiling时长,单位为分钟,不设置或设置为0则不进行profiling。
如果想对特定进程进行profiling,可以填写对应的pid;不填写默认对占用内存最大的java进程进行profiling
单击执行诊断。
重要开启应用内存profiling需要先对实例或Pod所在实例进行纳管。
开启应用内存profiling有一定性能、内存开销,内存占用根据符号大小占用50 - 300MB。.
在诊断记录区域,单击查看报告。

诊断报告
基础信息
基础信息部分包含单次诊断的基本信息,包括诊断实例ID(资源ID)、诊断项、诊断报告ID及诊断发起时间。
诊断结论
若诊断到内存使用异常,将会把异常信息显示在本章节。
诊断建议
如果当前系统的内存使用异常,会给出进一步排查问题的建议。
诊断详情
内存占用分析
通过三个饼状图展示了内存使用分布、内核态内存使用分布和用户态内存使用分布。

应用内存使用排序
在应用内存排序中可以找到实例或Pod中占用内存较高的java进程。

文件缓存占用排序
列出当前系统文件缓存占用最多的30个文件,包含文件的名称、文件被缓存大小(Cached)、文件关联的任务(若当前文件有关联任务则列出,没有则显示为空)。

共享内存缓存占用排序
列出当前系统共享内存缓存占用最多的30个文件。包含文件的名称、文件被缓存大小(Cached)、共享内存类型以及文件关联的任务(若当前文件有关联任务则列出,没有则显示为空)。

查看Java应用内存分布,选择需要查看的Java进程Pid

Java进程信息概览 & Java进程所在Pod/容器信息
展示了Java进程的基本信息,包括进程Pid、JVM内存使用量(即JVM视角的内存使用量)、Java进程内存使用量(可以理解为进程实际占用内存),进程匿名用量以及进程文件内存用量。

如果选用诊断Java进程所在Pod模式,还会展示Pod以及容器的RSS和WorkingSet内存占用。

Java进程内存详情
通过三个饼状图展示了Java堆内内存使用详情(JVM视角)、Java非堆内内存使用详情(JVM视角)和 Java进程实际内存使用详情;从而直观地看出在JVM视角下以及Java内存实际占用中,哪部分内存占用较大。

堆内对象内存占用排序(Top10)
列出当前JVM堆内占用内存排名前10的类的类名、类实例数和类实例占用的大小之和。

类加载器(classloader)加载数量排序(Top10)
列出当前加载类数排名前十的类加载器(classloader)的名称、加载类的数量以及加载器实例数量。

JNI(Java Native Interface)内存分配火焰图
若开启了JNI(Java Native Interface)内存分配profiling,列出当前Java进程JNI内存分配调用火焰图,火焰图中为所有分配JNI内存的调用路径。(由于是采样采集,火焰图中的内存大小不代表实际分配大小。)开启应用内存profiling有一定性能、内存开销,内存占用根据符号大小占用50 - 300MB。

只有发起诊断时选择开启JNI(Java Native Interface)内存分配profiling,等待对应时长后再打开诊断报告,火焰图数据才会展示。
JNI(Java Native Interface)内存泄漏火焰图
若开启了JNI(Java Native Interface)内存分配profiling,列出当前Java进程JNI内存泄漏调用火焰图,火焰图中为所有可能存在JNI内存泄漏的分配调用路径。(由于是采样采集,火焰图中的内存大小不代表实际分配大小。)开启应用内存profiling有一定性能、内存开销,内存占用根据符号大小占用50 - 300MB。.

只有发起诊断时选择开启JNI(Java Native Interface)内存分配profiling,等待对应时长后再打开诊断报告,火焰图数据才会展示。
实践案例
容器化在现阶段已成为构建企业IT架构的最佳实践。云原生容器化部署架构已成为兼具高效运维及成本控制的行业标准。容器化屏蔽了IDC基础设施和云资源,但同时也带来了容器引擎层的不透明性,常常出现内存黑洞、内存占用高、内存泄漏、抖动延时和cgroup泄露等问题。通过使用内存全景分析,可以使系统内存变得可维护、可测试和可追踪,从而将系统及容器内的缓存和共享内存归属到具体的文件名。
Kubernetes环境中容器Working Set较高的问题
Kubernetes采用内存工作集(Working Set)对容器的内存使用进行监控和管理。当容器的内存使用量超过设定的内存限制或节点出现内存压力时,Kubernetes将依据工作集的情况决定是否驱逐或终止相应的容器。
Working Set = 匿名内存 + active_file
匿名内存通常是通过new、malloc或mmap等方式进行分配,而active_file则是由进程在读写文件时引入的。程序对于这类内存的使用往往存在不透明的情况,容易发生问题。
问题现象
容器监控系统发现其Kubernetes集群中某个Pod的工作集内存持续增加,但应用所使用的内存并未显著上升,因此无法准确定位导致工作集内存使用增加的具体原因。

诊断分析
针对上述场景,使用Alibaba Cloud Linux控制台内存全景分析功能诊断Pod所在的ECS节点,诊断结果如下图所示。


根据诊断建议,可以确定问题源于业务程序在容器的/var/log目录下创建并读写日志文件,从而产生了文件缓存。由于Pod内的工作集(Workingset)内存过高,导致Pod的内存达到限制,进而触发了直接内存回收,造成了业务进程的阻塞。
解决方案
根据诊断结论,可通过以下方式解决内存过高的问题。
执行以下命令,主动释放缓存。
sudo sh -c 'echo 1 > /proc/sys/vm/drop_caches'如果缓存文件不是必需的,可以手动删除以释放缓存空间。
使用ACK集群的内存QoS功能。
共享内存较高的问题
问题现象
用户在运行时间较长的机器上执行free -h命令时剩余内存较少,buff/cache占用较多,执行sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'命令主动释放内存。使用该方法可以回收部分缓存,但仍有大量的cache占用没有释放。
诊断分析
针对上述场景,使用Alibaba Cloud Linux控制台内存全景分析功能诊断目标ECS实例,诊断结果如下图所示。


诊断结论给出了简明的分析结论。
根据诊断建议的引导,通过查看共享内存缓存占用排序可以看到共享内存缓存占用最大的前30个文件,且前几个共享内存的文件只有160 KB,因此可以证明诊断结论中给出的系统中存在大量小的共享内存文件的泄露点。
解决方案
根据上述分析过程,可以确认用户在该目录下创建了共享内存文件,且未及时释放所致。结合实际业务需求,需要评估是否存在内存泄漏,并对泄漏的共享内存文件进行删除,以释放占用的内存。
Pod OOM/内存占用高或Java进程内存占用高,但是JVM监控显示内存使用量不高的问题
问题现象
容器监控系统发现其Kubernetes集群中某个Java业务Pod的RSS内存持续增加,增加到一定程度后发生OOM。

但是通过JVM监控,堆内/堆外的内存使用量却比容器监控显示的RSS占用少了将近100MB;需要查明这差距的100MB内存究竟是被什么占用的。

诊断分析
针对上述场景,使用Alibaba Cloud Linux控制台内存全景分析诊断相关业务Pod,诊断结果如下图所示:

从诊断结论和诊断建议中,可以得知存在JNI(Java Native)内存泄漏(由于JNI内存使用量通常不会被JVM统计,所以这也是RSS比JVM内存大的主要原因之一)。

解决方案
再次发起诊断并开启JNI内存profiling。诊断完成后等待对应的profiling时长,然后再查看诊断报告。

通过JNI内存分配和泄漏火焰图可以看到,由于代码中创建了大量java.util.zip.Deflater,但是却没有正确释放导致出现了JNI内存泄漏,通过将代码中的泄漏点进行优化,问题得到解决。