内存泄漏面面谈

2024-05-29 04:20
文章标签 内存 泄漏 面谈

本文主要是介绍内存泄漏面面谈,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

主要介绍了内存泄漏的关注点是对象,对内存问题进行了分类并且确定本文关注点是内存泄漏,15种内存泄漏判断方式,hprof文件的用法和分析过程,以及memory profiler工具一些基本概念,最后提到了如何触发内存泄漏问题

内存泄漏的关注点——对象占据的内存

  • 本该回收的对象,无法被垃圾处理器回收;
  • 程序不再使用的对象,无法被垃圾处理器回收;
  • 在页面生命周期销毁后,页面持有、创建过的对象无法被垃圾处理器回收;
  • 在任务(线程、Service、广播)结束后,任务持有、创建过的对象无法被垃圾处理器回收

Android内存问题概述

内存抖动的表现形式:

  1. 忽高忽低,锯齿状

内存泄漏的表现形式:

  1. 页面或任务已经结束,相关的对象仍然被GC root索引,导致垃圾回收器无法回收,内存片段仍然存在

内存溢出的表现形式:

  1. App可用内存已到达系统规定的上限,如X型号手机规定单个App最大可分配内存为196mb
  2. 系统能为App分配的内存不足,系统可分配内存已经到达上限,如系统可用只有1mb,app需要20mb

Android中内存泄漏的判断方式

判断一个对象是否无法被回收,最佳的判断方式是定义清楚这个对象预期的生命周期,通常对象是随着页面、任务的生命周期产生和消亡的,Android中可以借此机制判断是否存在泄漏现象:
PS:“是否存在于hporf文件里”,是笔者用于等价替换原文“未被回收”的字样

  1. Activity:通过查看Activity#mDestroyed属性来判断Activity是否已经销毁,如果为true,表明该Activity已经被标记为销毁状态,此时hprof文件中若仍然存在此Activity,则表明这个Activity占据的内存处于泄漏状态;
  2. Fragment:通过Fragment#mFragmentManager属性来判断该Fragment是否处于无用状态,如果mFragmentManager为空,且hprof文件中若仍然存在此Fragment,则表明Fragment占据的内存处于泄漏状态;
  3. View:通过un wrapper#mContext获得Activity,如果Activity不为空,则按照判断Activity的方式判断Activity是否泄漏
  4. ContextWrapper:通过unwrapper ContextWrapper获得Activity,如果Activity不为空,则按照判断Activity的方式判断Activity是否泄漏
  5. Dialog,通过判断mDecor是否为空。mDecor为空,表明Dialog处于不被引用的状态,mDecor仍然存在在hporf里且为空,则表明Dialog泄漏了
  6. MessageQueue:通过判断MessageQueue#mQuitting或mQuiting是否退出,如果该值是true且未被回收,则认为是泄漏。
  7. ViewRootImpl:通过ViewRootImpl是否为空来判断,为空表明处于无用状态,为空且未被回收则被认为是泄漏
  8. Window:通过Window#mDestroyed来判断window是否处于无用状态,mDestroyed为true且未被回收,则认为是泄漏
  9. Toast:拿到mTN,通过mTN#mView是否为空来判断当前Toast是否已经hide,如果mView为空,表明Toast已经hide,此时Toast未被回收则认为是泄漏
  10. Editor:Editor是用于TextView处理editable text的辅助类,通过ditor#mTextView为空来判断Ediator是否处于无用状态;如果mTextView为空且未被回收则认为Editor泄漏了
    内存泄漏的典型 场景
  11. 非静态内部类、匿名内部类持有外部类对象的引用:常见的如Listener、CallBack、Handler、Dialog
  12. 非静态的Handler,持有Activity,Message持有Handler,Message被MessageQueue持有,MessageQueue持久存在,导致Activity不会被释放
  13. 资源对象未关闭:数据库连接、Cursor、IO流使用完后未close
  14. 属性动画:未及时使用cancel关闭;Animator持续存在,导致Animator持有的Activity、Fragment、View泄漏(Animator#updateListener一般都是匿名内部类,匿名内部类的问题参考场景1)
  15. 逻辑问题:广播监听后未及时解注册;

Hprof文件

Hprof文件导出

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

Heap分区:

  1. app heap:当前App在堆中占据的内存
  2. image heap:系统启动镜像,包括启动期间预加载的类
  3. zygote heap:所有App的父进程,所有App共享zygote的内存空间,zygote预加载了许多资源和代码,供所有App读取

Instance View:

  1. depth:从gc root到当前对象的引用链最短深度。被gc root引用到的对象不会被回收。
  2. 个人收获:depath = 0,表示不被gc root引用,即会被垃圾回收器回收。
  3. 个人收获:常见gc root有5种——局部变量、Activity threads、静态变量、JNI引用、类加载器
  4. native size:native对象占据的内存大小
  5. shallow size:对象本身占用的内存,何为对象本身?不包括它引用的其他实例
  6. 个人收获:shallow size = 类定义+ 父类变量所占空间大小 + 类成员变量所占空间 + [ alignment]
  7. 类定义:固定为8Byte
  8. 父类变量所占空间大小:当前类继承了其他类的成员变量,显然这些变量是占用空间的
  9. 自身变量:当前类的成员变量,如果是基本数据类型,则按基本类型计算;如果是引用数据类型,则固定为4byte,当前类仅持有变量名,
  10. alignment:指位数对齐,目的是让shallow zie的值为8的倍数,如某个类A,前三项计算结果未15byte,则shallo size为了达到8的倍数,会设置一个alignment值,凑够16byte。
  11. retained size:Retained Size是指, 当实例A被回收时, 可以同时被回收的实例的Shallow Size之和

Instance View易混淆概念:

shallow size:
Shallow Size是指实例自身占用的内存, 可以理解为保存该’数据结构’需要多少内存, 注意不包括它引用的其他实例
retained size:
实例A的Retained Size是指, 当实例A被回收时, 可以同时被回收的实例的Shallow Size之和
在这里插入图片描述
图中A, B, C, D四个实例, 为了方便计算, 我们假设所有实例的Shallow Size都是1kb
删除D实例:垃圾回收期会移除D实例;D实例的Retained Size=Shallow Size=1kb
删除C实例:垃圾回收器会移除C和D实例;C实例的Retained Size = C实例的Shallow Size + D实例的Shallow Size = 2kb
删除B实例:垃圾回收器会移除B实例,因为C仍然被A引用,所以C不会被移除,同理D也不会被移除;B实例的Retained Size=Shallow Size=1kb
删除A实例:垃圾回收器会移除B、C、D实例;A实例的Retained Size=4kb

怎么从prof文件内分析内存泄漏?

熟能生巧——memory profiler

实时预览功能区:

在这里插入图片描述

Hprof文件预览区:

在这里插入图片描述

怎么触发泄漏

  1. 旋转屏幕
    在不同的 activity 状态下,先将设备从竖屏旋转为横屏,再将其旋转回来,这样反复旋转多次。旋转设备经常会使应用泄漏 Activity、Context 或 View 对象,因为系统会重新创建 Activity,而如果应用在其他地方保持对这些对象其中一个的引用,系统将无法对其进行垃圾回收。
  2. 切换App至前台
    在不同的 Activity 状态下,在应用与其他应用之间切换(导航到主屏幕,然后返回到您的应用)。
  3. 断开后链接网络
  4. 锁屏后亮屏
  5. 频繁操作
    1. 频繁点击按钮,如编辑用户信息,点击保存按钮,触发保存业务
    2. 频繁进入页面,如重复进入-退出某个页面
    3. 频繁刷新页面,如重复下拉加载更多

这篇关于内存泄漏面面谈的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1012628

相关文章

NameNode内存生产配置

Hadoop2.x 系列,配置 NameNode 内存 NameNode 内存默认 2000m ,如果服务器内存 4G , NameNode 内存可以配置 3g 。在 hadoop-env.sh 文件中配置如下。 HADOOP_NAMENODE_OPTS=-Xmx3072m Hadoop3.x 系列,配置 Nam

JVM内存调优原则及几种JVM内存调优方法

JVM内存调优原则及几种JVM内存调优方法 1、堆大小设置。 2、回收器选择。   1、在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM。   2、对JVM内存的系统级的调优主要的目的是减少

JVM 常见异常及内存诊断

栈内存溢出 栈内存大小设置:-Xss size 默认除了window以外的所有操作系统默认情况大小为 1MB,window 的默认大小依赖于虚拟机内存。 栈帧过多导致栈内存溢出 下述示例代码,由于递归深度没有限制且没有设置出口,每次方法的调用都会产生一个栈帧导致了创建的栈帧过多,而导致内存溢出(StackOverflowError)。 示例代码: 运行结果: 栈帧过大导致栈内存

理解java虚拟机内存收集

学习《深入理解Java虚拟机》时个人的理解笔记 1、为什么要去了解垃圾收集和内存回收技术? 当需要排查各种内存溢出、内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就必须对这些“自动化”的技术实施必要的监控和调节。 2、“哲学三问”内存收集 what?when?how? 那些内存需要回收?什么时候回收?如何回收? 这是一个整体的问题,确定了什么状态的内存可以

NGINX轻松管理10万长连接 --- 基于2GB内存的CentOS 6.5 x86-64

转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=190176&id=4234854 一 前言 当管理大量连接时,特别是只有少量活跃连接,NGINX有比较好的CPU和RAM利用率,如今是多终端保持在线的时代,更能让NGINX发挥这个优点。本文做一个简单测试,NGINX在一个普通PC虚拟机上维护100k的HTTP

PHP原理之内存管理中难懂的几个点

PHP的内存管理, 分为俩大部分, 第一部分是PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用的层面的管理. 而第二部分就是今天我要介绍的, zend_alloc中描写的关于PHP自身的内存管理, 包括它是如何管理可用内存, 如何分配内存等. 另外, 为什么要写这个呢, 因为之前并没有任何资料来介绍PHP内存管理中使用的策略, 数据结构, 或者算法. 而在我们

string字符会调用new分配堆内存吗

gcc的string默认大小是32个字节,字符串小于等于15直接保存在栈上,超过之后才会使用new分配。

PHP内存泄漏问题解析

内存泄漏 内存泄漏指的是在程序运行过程中申请了内存,但是在使用完成后没有及时释放的现象, 对于普通运行时间较短的程序来说可能问题不会那么明显,但是对于长时间运行的程序, 比如Web服务器,后台进程等就比较明显了,随着系统运行占用的内存会持续上升, 可能会因为占用内存过高而崩溃,或被系统杀掉 PHP的内存泄漏 PHP属于高级语言,语言级别并没有内存的概念,在使用过程中完全不需要主动申请或释放内

C++学习笔记----6、内存管理(四)---- 通常的内存陷阱(2)

3、Windows环境下使用Visual C++发现并修复内存渗露         内存渗露很难跟踪是因为你无法很容易地看着内存并且看到什么对象处于使用中,一开始在哪儿分配的内存。然而,是有程序可以为你做到这一点的。内存渗露检测工具有昂贵的专业软件包,也有免费下载的工具。如果你是在Microsoft Visual C++环境下工作,它的排错工具库有内建的对于内存渗露检测的支持。该内存检测默认没有

控制台和MFC中内存泄露工具vld的使用

最近想检测下项目中内存泄露的情况,选中了vld这款。在查找使用方法的时候,大都是控制台下的示例,添加到main函数所在的源文件上。换成MFC就纠结了,不知道添加到哪里去。本文记录控制台和MFC中的使用vld过程。    vld资源:    1)、大家可以移步下边的网址下载:     http://vld.codeplex.com/releases/view/82311    2