Android-Daily-Interview icon indicating copy to clipboard operation
Android-Daily-Interview copied to clipboard

2019-04-02:谈谈Android中内存优化的方式?

Open Moosphan opened this issue 5 years ago • 14 comments

Moosphan avatar Apr 02 '19 01:04 Moosphan

关于内存泄漏,一般像单例模式的使用不当啊、集合的操作不当啊、资源的缺乏有效的回收机制啊、Handler、线程的使用不当等等都有可能引发内存泄漏。

  1. 单例模式引发的内存泄漏: 原因:单例模式里的静态实例持有对象的引用,导致对象无法被回收,常见为持有Activity的引用 优化:改为持有Application的引用,或者不持有使用的时候传递。
  2. 集合操作不当引发的内存泄漏: 原因:集合只增不减 优化:有对应的删除或卸载操作
  3. 线程的操作不当引发的内存泄漏: 原因:线程持有对象的引用在后台执行,与对象的生命周期不一致 优化:静态实例+弱引用(WeakReference)方式,使其生命周期一致
  4. 匿名内部类/非静态内部类操作不当引发的内存泄漏: 原因:内部类持有对象引用,导致无法释放,比如各种回调 优化:保持生命周期一致,改为静态实例+对象的弱引用方式(WeakReference)
  5. 常用的资源未关闭回收引发的内存泄漏: 原因:BroadcastReceiver,File,Cursor,IO流,Bitmap等资源使用未关闭 优化:使用后有对应的关闭和卸载机制
  6. Handler使用不当造成的内存泄漏: 原因:Handler持有Activity的引用,其发送的Message中持有Handler的引用,当队列处理Message的时间过长会导致Handler无法被回收 优化:静态实例+弱引用(WeakReference)方式 内存溢出: 原因: 1.内存泄漏长时间的积累 2.业务操作使用超大内存 优化: 1.调整图像大小后再放入内存、及时回收 2.不要过多的创建静态变量

Ssuiyingsen avatar Apr 02 '19 01:04 Ssuiyingsen

总结为一张图:

企业微信截图_3522bb02-32a8-4682-acfb-5758cae79088

Moosphan avatar Apr 02 '19 11:04 Moosphan

真正遇到过的内存溢出,是有一次查表,总共有几百M的数据被我一次性查出来,拿到这些数据后进行了一个StringBuffer的拼接,才0.5M就OOM了。后来处理方式就是每次拿10条数据库里面的东西,用完就=null。

q514414232 avatar Apr 03 '19 01:04 q514414232

内存优化,上面的都将的差不多了,那我说一下不一样的 其实性能优化的大多数方案都会侧面的有 内存优化的功能 比如:apk包体积优化,就会减少应用所需系统内存,还有 界面优化(层级减少、界面尽量不刷新或者局部刷新)也会优化内存,

979451341 avatar Apr 03 '19 03:04 979451341

看了大家的回答,感觉都讲得很不错。我这里说几个大家在开发中关于内存优化的几个细节。

  • 循环中尽可能不要创建较大的对象,列入bitmap。这会引起内存抖动。
  • 自定义View避免在onDraw中创建对象,因为自定义Viewon的onDraw方法会被频繁调用。创建对象,甚至较大的对象,会导致内存增加,甚至内存抖动。
  • cursor和流的及时关闭,特别是异常处理。一定要写finally里关闭流。
  • 避免静态内部类的引用。比如A类中有静态变量B。这是只要B被应用,就会导致A也不能回收。
  • 图片尽量使用软引用。较大的图片可以通过bitmapFactory缩放后再使用。并及时recycler.另外加载较大的图片尽可能不要使用setImageResourse,BitmapFactory.decordeResource和setImageBitmap方法。这些方法返回的是Bitmap对象。占用内存较大。可以使用BitmapFactory.decodeStream配合BitampFactory.Options对图片进行缩放,然后显示。
    ...
    其实关于内存的优化还有好多,欢迎大家补充。

MoJieBlog avatar Apr 19 '19 13:04 MoJieBlog

2.集合操作不当引发的内存泄漏 (1)对于HashMap,不使用动态改变hashCode的作为key对象 (2)对于HashSet,可以重写对象的equal和hashCode方法,增减特定的key的hashCode,使得每一个对象唯一 (3)如果发现remove之后,集合的数目没有改变,对于HashMap可以进行SetKey排查

nealkafuly avatar Nov 14 '19 07:11 nealkafuly

由于JVM有垃圾回收机制,因此,java内存要注意的问题相对c语音就大幅减少。主要可分为内存泄漏和内存溢出。

1,内存泄漏,本质是:生命周期长的对象持有了生命周期短的对象的引用。 常见场景: 1)资源对象未关闭导致内存泄漏,例如File、Cursor 2)静态类强引用,例如:Handler、webview、广播注册 2,内存溢出,本质是:APP内存超过了系统的上限 常见场景: 1)创建了超大文件,例如:大的图片一次性加载、text文件一次性加载 2)申请内存的速度超出了gc的速度,例如:递归没有终止、循环创建大量对象(线程)、大量的内存泄漏累积

内存优化,针对这两种情况进行注意就可以了,定期对APP进行内存检查即可。 当然,还有一种内存的兜底方案: 实现低内存状态回调,当系统内存不足,调用api时,执行自动重启APP、杀掉推送、关闭后台service等等操作

yline avatar Dec 20 '19 06:12 yline

  • 避免静态内部类的引用。比如A类中有静态变量B。这是只要B被应用,就会导致A也不能回收。 没明白你的意思,难道要用非静态内部类避免内存泄漏

pinpoy avatar Feb 24 '20 06:02 pinpoy

  • 避免静态内部类的引用。比如A类中有静态变量B。这是只要B被应用,就会导致A也不能回收。 没明白你的意思,难道要用非静态内部类避免内存泄漏

A类中有静态变量B,B被引用。并不会导致A类对应的对象不能回收。。 例如: class A{ public static B mB = new B(); }

使用: A a = new A(); 这个a和mB之间没有引用的关系。

你使用的时候也是:A.mB而不是a.mB

yline avatar Feb 26 '20 07:02 yline

  • 少用枚举类型
  • 优先使用Parcelable而不是Serializable
  • 在onDraw方法中不要创建对象
  • 给RecyclerView的item设置点击事件时使用同一个listener对象

aositeluoke avatar Dec 05 '20 06:12 aositeluoke

为什么这么多说软引用的,谷歌都不推荐 https://blog.csdn.net/zhangphil/article/details/80634204, 安卓开发中也不存在必须要用的软引用的地方,要么就硬引用,要么就被释放,不需要模棱两可

lt-123 avatar Jul 12 '21 07:07 lt-123

导致内存泄漏的原因只要有以下几种 1单例静态实例使用对象的引用 例:单例静态实例中使用了Activity context 解决方法:单例静态实例中不使用Activity context 而是使用application context 2资源末回收
例:数据库 文件读取流末关闭 解决方法:及时关闭数据库 文件读取流末关闭 3注册事件末注销 例:广播事件 EventBus注册后 无使用不注销掉 解决方法:无使用注销掉注册事件 4线程池的对象引用在后台执行 5匿名内部类/非静态内部类操作不当 例:在Activity中创建一个内部类handle 因为在发送消息后 handle的message持有Activity的对象引用 而message又放在消息队列中等待轮询处理 Activity可能退出后handle可能还末处理或者正在处理 这样就会导致Activity无法被回收 导致内存泄漏 解决方法:使用静态内部类+弱引用 6集合只增不减 例:当一个对象放入到ArrayList集合中 那这个集合就持有该对象的引用 当我们不需要这个对象时如果没有将它从集合中移除 这样只要这个集合还在这个对象就已经造成内存泄漏 解决方法:无使用的集合对象 从集合remove,或者clear集合,以避免内存泄漏。

mlinqirong avatar Dec 24 '21 08:12 mlinqirong

为什么这么多说软引用的,谷歌都不推荐 https://blog.csdn.net/zhangphil/article/details/80634204, 安卓开发中也不存在必须要用的软引用的地方,要么就硬引用,要么就被释放,不需要模棱两可

文章已经不在了

yihu5566 avatar Jun 16 '22 08:06 yihu5566

这是来自QQ邮箱的假期自动回复邮件。  

luckilyyg avatar Jun 16 '22 08:06 luckilyyg