android中hprof文件分析

article/2025/10/13 22:08:42

Hprof基本概念

hprof最初是由J2SE支持的一种二进制堆转储格式,hprof文件保存了当前java堆上所有的内存使用信息,能够完整的反映虚拟机当前的内存状态。
格式
在这里插入图片描述
Hprof文件由FixedHead和一系列的Record组成,Record包含字符串信息、类信息、栈信息、GcRoot信息、对象信息。每个Record都是由1个字节的Tag、4个字节的Time、4个字节的Length和Body组成,Tag表示该Record的类型,Body部分为该Record的内容,长度为Length。

Android中的hprof

在Android设备上,我们可以通过两种方式生成当前进程的hprof文件

通过调用Debug.dumpHprofData(String filePath)方法来生成hprof文件
通过执行shell命令adb shell am dumpheap pid /data/local/tmp/x.hprof来生成指定进程的hprof文件到目标目录

然而Android平台上的hprof文件和标准Java的hprof定义有一些区别,主要是版本号不一样,而且增加了一些特殊Tag,在art/runtime/hprof/hprof.cc中有如下定义
在这里插入图片描述
可以看出Android增加了额外的9个HeapTag,其中比较重要的是HPROF_HEAP_DUMP_INFO。Android上将java堆分为Heap-App、Heap-Image、Heap-Zygote三块,这个Tag的作用是切换当前的堆,该Tag后面紧跟着一个4个字节的堆id和一个堆名称id。
比如出现一个HPROF_HEAP_DUMP_INFO Record,且该Record表示Heap-Image,那么表示后续所有Record中的类、对象、GCRoot对象均在Heap-Image中存储,直到下一个HPROF_HEAP_DUMP_INFO出现为止。

内存泄漏

内存泄漏指的是一个本该被回收的对象因为某些原因导致其不能被回收,通俗来说就是该对象理论上不再使用,但是仍无法被回收。

Android中的泄漏对象

判断一个对象是否泄漏首先要判断该对象是否不再使用,想要判断这一点则需要对象有明显的生命周期,在Android中有以下对象可以判断是否泄漏:

1、Activity: 通过Activity的mDestroyed属性来判断该Activity是否已经销毁,如果已经销毁且未被回收则认为是泄漏
Fragment: 通过Fragment的mFragmentManager是否为空来判断该Fragment是否处于无用状态,如果mFragmentManager为空且未被回收则认为是泄漏。

2、View: 通过unwrapper mContext获得Activity,如果存在Activity,则判断该Activity是否泄漏。

Editor: Editor指的是android.widget包下的Editor,是用于TextView处理editable text的辅助类,通过mTextView是否为空来判断Editor是否处于无用状态,如果mTextView为空且未被回收则认为是泄漏。

3、ContextWrapper: 通过unwrapper ContextWrapper获得Activity,如果存在Activity,则判断该Activity是否泄漏。

4、Dialog: 通过mDecor是否为空判断该Dialog是否处于无用状态,如果mDecor为空且未被回收则认为是泄漏。

5、MessageQueue: 通过mQuitting或者mQuiting(应该是历史原因,前期拼写错误为mQuiting,后来改正)来判断MessageQueue是否已经退出,如果已经退出且未被回收则认为是泄漏。

ViewRootImpl: 通过ViewRootImpl的mView是否为空来判断该ViewRootImpl是否处于无用状态,如果mView为空且未被回收则认为是泄漏。

6、Window: 通过mDestroyed来判断该Window是否处于无用状态,如果mDestroyed为true且未被回收则认为是泄漏。
Toast: 拿到mTN,通过mTN的mView是否为空来判断当前Toast是否已经hide,如果已经hide且未被回收则认为是泄漏。

泄漏的形式

泄漏的本质就是无用对象被持有导致无法回收,具体的形式有如下几种:

1、非静态内部类、匿名内部类持有外部类对象引用: 一般为用于回调的Listener,该Listener被别的地方持有,间接导致外部类对象被泄漏。
2、Handler: 在Activity中定义Handler对象的时候,Handler持有Activity同时Message持有Handler,而Message被MessageQueue持有,最终导致Activity泄漏。

3、资源对象未关闭: 数据库连接、Cursor、IO流等使用完后未close。

4、属性动画: 使用ValueAnimator和ObjectAnimator的时候,未及时关闭动画导致泄漏。Animator内部向AnimationHandler注册listener,AnimationHandler是一个单例,如果不及时cancel,会导致Animator泄漏,间接导致Activity/Fragment/View泄漏(比如Animator的updateListener一般都以匿名内部类实现)

5、逻辑问题: 注册监听器之后未及时解注册,比如使用EventBus的时候没有在合适的时候进行解注册

profiler使用

通过下载hprof文件,解压缩后,直接拖到Android studio中,可以通过Android studio中的profiler工具进行分析,如下图:
1、Heap Dump
1、筛选
左边区域可以通过筛选查看到泄漏的activity或者fragment,在Android中的泄漏主要是activity或者fragment有生命周期的类泄漏。
2、Heap区分
Heap 中主要分为三种:
在这里插入图片描述
1、app heap
当前APP从堆中分配的内存
2、image heap
系统启动映像,包含启动期间预加载的类。 此处的分配保证绝不会移动或消失
3、zygote heap
zygote是所有APP进程的母进程,linux 的进程使用COW技术,所有的APP共享zygote的内存空间,因此堆的话也继承了,并且zygote的这些空间不允许写入,为了加快java的启动和运行速度,zygote在启动时预加载了许多资源和代码,这样可以提高APP的运行速率.
源码

enum HprofHeapId {HPROF_HEAP_DEFAULT= 0,HPROF_HEAP_ZYGOTE= 'Z',HPROF_HEAP_APP= 'A',HPROF_HEAP_IMAGE= 'I',
};if (space->IsZygoteSpace()) {heap_type= HPROF_HEAP_ZYGOTE;VisitRoot(obj, RootInfo(kRootVMInternal));} else if (space->IsImageSpace() && heap->ObjectIsInBootImageSpace(obj)) {// Only countobjects in the boot image as HPROF_HEAP_IMAGE, this leaves app image objects as// HPROF_HEAP_APP.b/35762934heap_type= HPROF_HEAP_IMAGE;VisitRoot(obj, RootInfo(kRootVMInternal));}} else {const auto* los = heap->GetLargeObjectsSpace();if (los->Contains(obj) && los->IsZygoteLargeObject(Thread::Current(), obj)) {heap_type= HPROF_HEAP_ZYGOTE;VisitRoot(obj, RootInfo(kRootVMInternal));}

2、Instance View

点击heap dump中具体的类,右边就会展示instance view
Instance view中主要展示对象相关的信息
在这里插入图片描述

1、Depth
depth是从gc roots到选中的当前对象的引用链最短长度。在java垃圾回收机制中,被gc roots引用到的对象不会被回收。如下图:在gc root 引用树之外的对象会被回收。
在这里插入图片描述
Android中gc root 主要分为下面几类:
在这里插入图片描述
2、Native Size
native对象的内存大小,这个值只有在Android 7.0以及更高的版本可见。
3、Shallow Size
对象本身占用的内存,不包括它引用的其他实例

Shallow Size = [类定义] + 父类fields所占空间 + 自身fields所占空间 + [alignment]

4、Retained Size
Retained Size是指, 当实例A被回收时, 可以同时被回收的实例的Shallow Size之和,所以进行内存分析时,应该重点关注Retained Size较大的实例; 或者可以通过Retained Size判断出某A实例内部使用的实例是否被其他实例引用.
如下图:
在这里插入图片描述
上图中:obj1的retained size=obj1+obj2+obj4的shallow size,注意由于obj3被gc roots直接引用,所以这个值不计算到obj1的retained size中。
在这里插入图片描述
如上图:obj1的retained size=obj1+obj2+ obj3+obj4的shallow size

3、Reference

reference里面主要是类的引用关系,可以通过引用关系,一层一层的查看类是如何泄漏的。

参考

1、Android中内存泄漏相关
2、hprof文件相关
3、profile分析内存泄漏


http://chatgpt.dhexx.cn/article/PCt9DDF6.shtml

相关文章

hprof 文件查看

https://www.jianshu.com/p/4e6e88f1d211 hprof 文件是 Java 的 内存快照文件(Heap Profile 的缩写),格式为 java_pid*.hprof 用于分析 OOM: OutOfMemoryError(堆)内存不足错误 是 JVM 设置 -XX:HeapDumpOnOutOfMemoryError 参数时打印的内容…

Java 内存溢出(二)使用 MAT 分析 .hprof 内存映像文件

目录 一、内存溢出时自动导出 .hprof 文件二、下载安装 MAT三、启动 MAT四、MAT 分析 hprof 文件1.Overview 概览2.Leak Suspects 溢出原因猜测3.Histogram 对象实例数量排序4.Dominator Tree 支配树 .hprof 文件: 是 java 项目的 Heap Dump 文件,也叫内…

Solr文档学习--Solrj的使用

首先启动solr solr.cmd startSolrClient 主要通过SolrClient来连接到Solr服务器 SolrClient有4个实现类 CloudSolrClient SolrJ client class to communicate with SolrCloud. Instances of this class communicate with Zookeeper to discover Solr endpoints for SolrClou…

solrj 对solr 的操作

使用SolrJ操作Solr会比利用httpClient来操作Solr要简单。SolrJ是封装了httpClient方法,来操作solr的API的。SolrJ底层还是通过使用httpClient中的方法来完成Solr的操作。 1、 首先,你需要添加如下jar包 其中apache-solr-solrj-3.4.0.jar、slf4j-api-1.6…

SolrJ的使用

CommonsHttpSolrServer CommonsHttpSolrServer 使用HTTPClient 和solr服务器进行通信。 Java代码 String url "http://localhost:8983/solr"; SolrServer server new CommonsHttpSolrServer( url ); String url "http://localhost:8983/solr";Sol…

sorl

solr: 层面搜索、命中醒目显示并且支持多种输出格式(包括 XML/XSLT 和 JSON 格式),Solr 可以阅读和使用构建到其他 Lucene 应用程序中的索引。 安装:http://blog.csdn.net/millery22/article/details/51446014 对外提…

Solr和Solrj的使用

Solr(4.10.3)&Solrj 部署环境 1.拷贝solr solr-4.10.3\example\solr 目录到【如E:/solr/】,重命名solr为solrhome 【E:/solr/solrhome】 solrhome:solr里面有几个文件 collection1:有一个默认名称为collection1的SolrCore索引库 conf:SolrCore运行配置信息 co…

SolrJ的查询

1.solr是一个全文检索引擎系统,通过部署到tomcat下就可以独立运行,通过http协议对外提供全文检索服务, 就是索引和文档的正删改查服务 2. solr直接操作索引库和文档库, 我们的业务系统中可以使用solrJ(solr的客户端,就是一堆jar包)来调用solr服务端, 让solr服务端操作文档库和…

使用solrJ操作solr常用方法

既然学的是java那么肯定需要用java代码来进行对solr的操作,如果知道在solr后台管理界面进行增删改查等操作,那么用solrJ操作solr会更好理解。 solrJ介绍 solrJ是一个用来访问solr的java客户端,提供了索引和搜索的方法(将一些常用…

solr快速上手:整合SolrJ实现客户端操作(九)

0. 引言 我们前面学习了solr的服务端基础操作,实际项目中我们还需要在客户端调用solr,就像调用数据库一样,我们可以基于solrJ来实现对solr的客户端操作 1. SolrJ简介 SolrJ 是 Solr官方提供的 Java 客户端库,主要用于与 Solr 服…

全文检索solr(五)Solrj的使用

什么是solrj solrj是访问Solr服务的java客户端,提供索引和搜索的请求方法,如下图: Solrj和图形界面操作的区别就类似于数据库中使用jdbc和mysql客户端的区别一样。 需求 使用solrj调用solr服务实现对索引库的增删改查操作。 环境准备 So…

Solr-Solrj简单使用

一、SolrJ简介 SolrJ是操作Solr的Java客户端&#xff0c;它提供了增加、修改、删除、查询Solr索引的Java接口。通过solrJ提供的API接口来操作solr服务&#xff0c;SolrJ底层是通过使用httpClient中的方法来完成Solr的操作。 二、依赖配置 <dependency><groupId>…

solrj

文章目录 1.什么是solrj?2.搭建工程2.1.导入相关jar包 3.对索引库做增删改查3.1.添加&#xff08;以实体类的方式&#xff09;添加方法 3.3.修改&#xff08;update&#xff09;3.4.删除以ID删除批量删除&#xff08;以ID&#xff09;以条件删除&#xff08;query&#xff09;…

Solr系列四:Solr(solrj 、索引API 、 结构化数据导入)

一、SolrJ介绍 1. SolrJ是什么&#xff1f; Solr提供的用于JAVA应用中访问solr服务API的客户端jar。在我们的应用中引入solrj&#xff1a; <dependency><groupId>org.apache.solr</groupId><artifactId>solr-solrj</artifactId><version>7…

solr学习之solrj

solrJ是访问Solr服务的JAVA客户端&#xff0c;提供索引和搜索的请求方法&#xff0c;SolrJ通常嵌入在业务系统中&#xff0c;通过solrJ的API接口操作Solr服务。 一 .maven的环境jar包配置 <!-- https://mvnrepository.com/artifact/org.apache.solr/solr-solrj --><d…

Pytorch实现逻辑斯蒂回归模型 代码实操

初学者学习Pytorch系列 第一篇 Pytorch初学简单的线性模型代码实操 第二篇 Pytorch实现逻辑斯蒂回归模型 代码实操 文章目录 初学者学习Pytorch系列前言一、先上代码二、测试结果1. 数据结果2.画图结果 总结 前言 上一篇的数据中&#xff0c;是这样子的例子 x_data代表的学习的…

回归分析(三)二项逻辑斯蒂回归模型

回归分析&#xff08;三&#xff09;二项逻辑斯蒂回归 学了一段时间突然又遇到逻辑斯蒂回归&#xff0c;结果发现已经忘完了&#xff0c;所以今天重新梳理一下。 &#xff08;1&#xff09;逻辑斯蒂分布 先看一下逻辑斯蒂分布函数 F ( x ) F(x) F(x)&#xff0c;其概率密度函数…

回归分析:逻辑斯蒂回归模型,可视化分类决策边界

文章目录 逻辑斯蒂回归模型逻辑斯蒂回归模型python案例 逻辑斯蒂回归模型 前面的例子都是在用线性模型解决回归任务&#xff0c;那么线性模型能否完成分类任务呢&#xff1f;相较于回归任务&#xff0c;分类任务的预测值是离散的&#xff0c;比如二分类问题&#xff0c;可以用…

机器学习:逻辑斯蒂回归

目录 逻辑回归模型介绍逻辑斯蒂分布二项逻辑斯谛回归模型目标函数 逻辑回归模型介绍 原理&#xff1a; 逻辑斯谛回归&#xff08;logistic regression&#xff09;是经典的分类方法&#xff0c;它属于对数线性模型&#xff0c;原理是根据现有的数据对分类边界线建立回归公式&a…

《PyTorch深度学习实践》06 逻辑斯蒂回归 代码

视频&#xff1a;06.逻辑斯蒂回归_哔哩哔哩_bilibili 参考文章&#xff1a;pytorch 深度学习实践 第6讲 逻辑斯蒂回归_会游泳的小雁的博客-CSDN博客 网络模型的基本框架 1步骤&#xff1a; 1.Prepare dataset 2.Design model using Class &#xff08;inherit from nn.Modul…