字节跳动应用性能监控帮助客户Java OOM崩溃率下降80%
本文将会从Java内存基础开始,详细介绍“基于Hprof内存快照的线上Java OOM 归因方案”的底层原理与技术细节,欢迎接入MARS-APMPlus 应用性能监控使用。
一、前言
二、Java 内存基础
2.1 Java 内存优化的重要性
2.2 为什么会Java OOM崩溃
Java Out Of Memory,字面意思是说Java 虚拟机的内存用完。Java有一个相关的异常类 java.lang.OutOfMemoryError,官方有如下说明:
Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.
- Java虚拟机都有哪些内存区域
- 垃圾回收器是如何工作回收内存的
- 每个对象占据多大的内存空间
- Java 虚拟机当前的内存空间状态以及OOM是如何发生的
2.1.1 Java虚拟机的内存区域
|
名称
|
说明
|
是否线程间共享
|
|
PC Register
|
称为程序计数器, 看作是当前线程所执行的字节码的行号指示器
|
否
|
|
JVM Stack
|
也称为虚拟机栈,记录每个栈帧(Frame)中的局部变量、方法返回地址等
|
否
|
|
Native Method Stack
|
本地 (原生) 方法栈,是调用操作系统原生本地方法时,所需要的内存区域
|
否
|
|
Heap |
堆内存区,也是 GC 垃圾回收的主要场所,用于存放类的实例对象
|
是
|
|
Method Area
|
方法区,主要存放类结构、类成员定义,static 静态成员等
|
是
|
|
Runtime Constant Pool
|
运行时常量池,比如:字符串等
|
是
|
2.1.2 垃圾回收器是如何工作回收内存的
2.1.3 对象占据多大的内存空间
Dominator Tree支配树, Dominator Tree有以下几个定义:
- 对象X
Dominator(支配)对象Y,当且仅当在对象树中所有到达Y的路径都必须经过X - 对象Y的直接
Dominator,是指在对象引用关系中距离Y最近的Dominator Dominator tree利用对象引用关系构建出来
Dominator tree的对应关系如下:
Dominator tree时,会A、B、C三个是平级的。
Dominator Tree能帮助我们快速的发现占用内存最大的块,也能帮我们分析对象之间的依赖关系。
ShallowSize:对象本身占用内存的大小。也就是对象头加成员变量(不是成员变量的值)的总和,如一个引用占用32或64bit,一个integer占4bytes,Long占8bytes等。常规对象(非数组)的Shallow Size 由其成员变量的数量和类型决定,数组的 Shallow Size 由数组元素的类型(对象类型、基本类型)和数组长度决定。例如E的Shallow Size,只是自身大小和他引用的G没有关系。RetainedSize:对象被垃圾回收器回收后能被GC从内存中移除的所有对象内存大小之和。相对于Shallow Size,Retained Size可以更精确的反映一个对象实际占用的大小(若该对象释放,Retained Size都可以被释放)。例如E到C的引用链断开后,会释放E、G这2个对象。这2个对象的所占内存之和就是E的Retained Size。
2.1.4 Java OOM的发生
java.lang.OutOfMemoryError: Failed to allocate a 65552 byte allocation with 23992 free bytes and 23KB until OOM, max allowed footprint 536870912, growth limit 536870912
OutOfMemoryError抛出的地方在系统源码文件/runtime/gc/heap.cc
//方法
void Heap::ThrowOutOfMemoryError(Thread* self, size_t byte_count, AllocatorType allocator_type)
//异常信息
oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free
<< " free bytes and " << PrettySize(GetFreeMemoryUntilOOME()) << " until OOM,"
<< " target footprint " << target_footprint_.load(std::memory_order_relaxed)
<< ", growth limit "
<< growth_limit_;
OutOfMemoryError异常。
- Runtime.getRuntime().maxMemory() : 当前虚拟机实例的内存使用上限
- Runtime.getRuntime().totalMemory() : 当前已经申请的内存,包括已经使用的和还没有使用的
- Runtime.getRuntime().freeMemory() : totalMemory中已经申请但是尚未使用的部分
- used=totalMemory() - freeMemory(): 已经申请并且正在使用的部分
- totalFree=maxMemory()-used: Java虚拟机还可以使用的部分
OutOfMemoryError异常。
2.3 Java内存相关工具
|
工具名称
|
介绍
|
优点
|
缺点
|
|
MAT
|
The Eclipse Memory Analyzer is a fast and feature-rich that helps you find memory leaks and reduce memory consumption.
|
分析功能强大
|
线下分析,需要自己采集Hprof文件
|
|
LeakCanary
|
LeakCanary is a memory leak detection library for Android.
|
可以接入App自动分析
|
线下分析,主要分析内存泄露
|
|
Android Studio Memory Profiler
|
可帮助用户识别可能会导致应用卡顿、冻结甚至崩溃的内存泄露和内存抖动
|
可以动态内存监控,也可以静态内存分析
|
线下分析,需要App debug模式
|
- 都是线下工具,线下复现Java OOM问题困难
- 自动化程度低,只能手动操作分析内存问题
- 都是单点工具,只能分析单个hprof文件,没法聚合找到核心问题
三、Java OOM归因方案
- 高度还原场景:可以拿到Java OOM时候的场景内存数据
- 自动化分析:可以自动化进行内存数据分析
- 聚合找到核心问题:可以根据问题特征聚合发现核心问题
- 隐私安全:因为是线上监控,所以需要满足用户隐私安全的要求
3.1 Hprof基础知识
3.1.1 Hprof介绍
3.1.2 Hprof结构
3.1.3 Hprof文件使用
3.2 方案概要
- 端SDK:负责Hprof文件的采集、裁剪、压缩及上报等
- 服务端:Hprof文件存储、还原、自动分析、结果Retrace、issue聚合,自动分配等
- 前端:问题展示包括内存泄露、大对象、类大对象等
3.3 方案原理
3.2.1 内存文件端上dump
- OOM之后还要再进行 dump 操作确实会容易dump失败。
- OOM时候App崩溃不可用,dump操作会在崩溃时候导致卡顿。
3.2.2 内存文件的裁剪和还原
- 规避隐私风险:Hprof保存了执行Dump时刻Java堆上所有的内存信息,包括存在内存中的账户信息等,这些敏感信息必须裁剪掉。
- 减小文件大小:因为堆内存不足而OOM的时候获到的Hprof文件,约等于设备单进程最大可用内存,一般文件比较大有几百M,大文件上传浪费用户流量、带宽以及导致上报成功率降低。
- 根据Hprof文件的格式进行分析,分析我们不需要关注的数据块
- 将文件映射进内存,根据文件格式找到想要裁剪的数据块
- 再次写入文件的时候不要写第2步找到的数据块
- 这样产生的Hprof文件就是裁剪后的
3.2.3 内存文件的自动化解析
- 内存泄露
- 大对象
- 小对象
3.2.3.1 内存泄露
private boolean mDestroyed;
final void performDestroy() {
mDestroyed = true;
xxx
}
3.2.3.2 大对象
if (object != null && object.getRetainedHeapSize() > MINIMAL){
// 算作大对象
}
3.2.3.3 类大对象
3.2.4 聚合和Retrace
3.2.4.1 聚合
3.2.4.2 Retrace
3.2.5 自动分配
当前在火山引擎的MARS-APMPlus 应用性能监控无法获取用户的仓库解析Class Owner,暂时无法自动分配。
3.2.6 总结
四、优化效果
4.1 内部效果
4.2 外部效果
五、接入使用
🔥 火山引擎 APMPlus 应用性能监控是火山引擎应用开发套件 MARS 下的性能监控产品。我们通过先进的数据采集与监控技术,为企业提供全链路的应用性能监控服务,助力企业提升异常问题排查与解决的效率。目前产品正在免费公测阶段,👉 戳这里了解更多产品信息。欢迎大家进行试用!