Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2019-03-12:一般什么情况下会导致内存泄漏问题? #3

Open
Moosphan opened this issue Mar 12, 2019 · 15 comments
Open

2019-03-12:一般什么情况下会导致内存泄漏问题? #3

Moosphan opened this issue Mar 12, 2019 · 15 comments

Comments

@Moosphan
Copy link
Owner

No description provided.

@Moosphan Moosphan added the underway the daily question is solving now label Mar 12, 2019
@Moosphan
Copy link
Owner Author

Moosphan commented Mar 13, 2019

  1. 资源对象没关闭造成的内存泄漏(如: CursorFile等)
  2. ListViewAdapter 中没有使用缓存的 ConvertView
  3. Bitmap 对象不在使用时调用recycle()释放内存
  4. 集合中对象没清理造成的内存泄漏(特别是 static 修饰的集合)
  5. 接收器、监听器注册没取消造成的内存泄漏
  6. ActivityContext 造成的泄漏,可以使用 ApplicationContext
  7. Handler 造成的内存泄漏问题(一般由于 Handler 生命周期比其外部类的生命周期长引起的)

@Moosphan Moosphan added finished and removed underway the daily question is solving now labels Mar 13, 2019
@chunzhenmilk
Copy link

chunzhenmilk commented Apr 11, 2019

楼上总结的不错,想纠正一点:2. ListView 的 Adapter 中没有使用缓存的 ConvertView。因为前两天刚看了ListView源码,ConvertView其实是滑出屏幕的View的缓存,不使用ConvertView会频繁创建新的View对象,只会造成内存溢出,而不是内存泄漏。这个问题我们首先要明白内存泄漏的真正原因:A对象引用B对象,但是A对象的生命周期比B对象的生命周期长的多,B生命周期到了还在被A引用,导致B对象不能回收,从而引起内存泄漏

@lx36301766
Copy link

纠正一点,bitmap早就不需要手动调用recycle了,可以看看这篇文章:https://www.jianshu.com/p/76bbdc4bcad8

@sukaidev
Copy link

sukaidev commented Apr 18, 2019

Android中常见的:资源对象未关闭、全局集合类强引用、广播接收器或是EventBus等未反注册、Context的错误使用以及Context与单例的问题、非静态内部类与Handler的问题。

@RedDargon
Copy link

需要被释放的资源没有被及时释放 就会造成内存泄漏 。
可能的场景有好些种 ,大多都是因为异步操作造成的 ,或者生命周期长的持有了生命周期短的引用。

1.handler 消息
2.非静态内部类
3.异步操作 还有AsyncTask 等
4.静态类持有非静态类 比如工具类莫名持有context
5.资源对象未关闭(File流 Cursor )
6.注册监听 未及时注销

@risechen
Copy link

risechen commented May 7, 2019

1、内存泄漏的根本原因在于生命周期长的对象持有了生命周期短的对象的引用
2、常见场景
(1)资源对象没关闭造成的内存泄漏(如: Cursor、File等)
(2)全局集合类强引用没清理造成的内存泄漏(特别是 static 修饰的集合)
(3)接收器、监听器注册没取消造成的内存泄漏,如广播,eventsbus
(4)Activity 的 Context 造成的泄漏,可以使用 ApplicationContext
(5)单例中的static成员间接或直接持有了activity的引用
(6)非静态内部类持有父类的引用,如非静态handler持有activity的引用
3、如何避免内存泄漏
(1)编码规范上:
①资源对象用完一定要关闭,最好加finally
②静态集合对象用完要清理
③接收器、监听器使用时候注册和取消成对出现
④context使用注意生命周期,如果是静态类引用直接用ApplicationContext
⑤使用静态内部类
⑥结合业务场景,设置软引用,弱引用,确保对象可以在合适的时机回收
(2)建设内存监控体系
线下监控:
①使用ArtHook检测图片尺寸是否超出imageview自身宽高的2倍
②编码阶段Memery Profile看app的内存使用情况,是否存在内存抖动,内存泄漏,结合Mat分析内存泄漏
线上监控:
①上报app使用期间待机内存、重点模块内存、OOM率
②上报整体及重点模块的GC次数,GC时间
③使用LeakCannery自动化内存泄漏分析
总结:
上线前重点在于线下监控,把问题在上线前解决;上线后运营阶段重点做线上监控,结合一定的预警策略及时处理
4、真的出现低内存,设置一个兜底策略
低内存状态回调,根据不同的内存等级做一些事情,比如在最严重的等级清空所有的bitmap,关掉所有界面,直接强制把app跳转到主界面,相当于app重新启动了一次一样,这样就避免了系统Kill应用进程,与其让系统kill进程还不如浪费一些用户体验,自己主动回收内存

@hyyaoming
Copy link

总的来说就是生命周期长的对象持有了生命周期短的对象,导致生命周期短的对象在回收时导致对象无法释放,从而导致内存泄漏。

@frinda
Copy link

frinda commented Aug 2, 2019

内存泄漏造成的原因
无非是生命周期长的对象持有生命周期短的对象的引用,造成生命周期短的对象使用完之后无法释放内存;

内存泄漏出现的场景:
非静态内部类(非静态内部类默认持有外部类的引用,例如Handler:消息队列里的消息持有handler的引用,handler作为内部类持有外部类的引用),注册未解绑(例如EventBUS),资源未关闭未释放(webview、Bitmap未释放),静态变量(例如单例模式),集合容器(通常把一些对象的引用加入到集合容器中)

解决办法
使用静态内部类或者把内部类独立出来,如果需要context,使用applicationcontext,如果需要引用外部类的变量,使用弱引用的方式

@ZHANGfeng-james
Copy link

从这个内存泄漏的主题,还可以引出的知识点:

  1. Java 中的 static 关键字;
  2. Java 中的 4 种引用(强、软、弱、虚引用);
  3. Java 内部类的使用;

@wangxuyang518
Copy link

1.非静态内部类(非静态内部类默认持有外部类的引用,例如Handler:消息队列里的消息持有handler的引用,handler作为内部类持有外部类的引用)
2.注册未解绑(例如EventBUS),
3.资源未关闭未释放(webview、Bitmap未释放)、
4.静态变量(例如单例模式),
5.集合容器(通常把一些对象的引用加入到集合容器中)

@Mr-taotao
Copy link

1.资源未关闭释放(如数据库操作未关流)
2.注册的监听未注销(如广播注册了,没有解绑)
3.非静态内部类持有外部类的引用(如Handler)
4.静态变量(如单例)
5.集合容器没有清空(如一些对象引用放到集合容器,ThreadLocal变量)

@manondidi
Copy link

非静态内部类对外部有一个引用
context被单例持有
context被静态变量持有
bitmap没回收
bus没反注册
资源对象没关闭(cursor)
总而言之就是 持有了 本该没有继续使用的对象,导致他无法释放, gcroot

检测方式有以下几种
1.leakCanary
原理是, 用activityfragmentlifecyclercallback 去监听acvivity 或者 fragment 的ondestory时机
并且弱引用持有他们, 把他们的弱引用关联到引用队列
引用队列的作用是, 当 和他关联的引用发生变化会被添加进这个引用队列
于是 当activity 或 fragment ondestory的时候 会去检测 这些弱引用是否被回收,如果没有则触发gc(此时肯定没有leak 肯定会被回收).如果弱引用还存在 则证明leak,把当前的内存信息dump出来,用square的另外一个第三方库 haha 来进行内存分析
2. 使用android studio 自带的profiler 进行内存分析,在退出当前activity的时候,看下时间线,当前的actvitiy的对象引用数有几个,如果不为0则 手动发起gc 看看是否 有减少,如果没有,则把当前内存快照dump出来,然后用 mat进行分析

@LillteZheng
Copy link

都忽略了内存泄漏的定义,应该是当GC来临时,本该释放回收的对象,因为被其他对象持有,导致无法释放;注意和内存溢出的区别

@zhangsen22
Copy link

这个问题应该从内存抖动,内存泄露,内存溢出三个纬度讲解,再结合线上和线下的监控手段

@mlinqirong
Copy link

内存泄漏原因
生命周期长的对象使用了生命周期短的对象的引用,造成生命周期短的对象使用完之后内存无法及时释放
比如说
数据库和文件操作完没有关闭
注册的事件没有注销掉
bitmap没有关闭
单例中的start成员使用了activity的引用
context不合理的使用

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests