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-04-02:谈谈Android中内存优化的方式? #18

Open
Moosphan opened this issue Apr 2, 2019 · 14 comments
Open

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

Moosphan opened this issue Apr 2, 2019 · 14 comments

Comments

@Moosphan
Copy link
Owner

Moosphan commented Apr 2, 2019

No description provided.

@Moosphan Moosphan added the underway the daily question is solving now label Apr 2, 2019
@Ssuiyingsen
Copy link

Ssuiyingsen commented Apr 2, 2019

关于内存泄漏,一般像单例模式的使用不当啊、集合的操作不当啊、资源的缺乏有效的回收机制啊、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.不要过多的创建静态变量

@Moosphan
Copy link
Owner Author

Moosphan commented Apr 2, 2019

总结为一张图:

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

@q514414232
Copy link

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

@979451341
Copy link

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

@Moosphan Moosphan added 内存优化 and removed underway the daily question is solving now labels Apr 11, 2019
@MoJieBlog
Copy link
Collaborator

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

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

...
其实关于内存的优化还有好多,欢迎大家补充。

@nealkafuly
Copy link

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

@yline
Copy link

yline commented Dec 20, 2019

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

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

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

@pinpoy
Copy link

pinpoy commented Feb 24, 2020

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

@yline
Copy link

yline commented Feb 26, 2020

  • 避免静态内部类的引用。比如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

@aositeluoke
Copy link

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

@lt-123
Copy link

lt-123 commented Jul 12, 2021

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

@mlinqirong
Copy link

导致内存泄漏的原因只要有以下几种
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集合,以避免内存泄漏。

@yihu5566
Copy link

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

文章已经不在了

@luckilyyg
Copy link

luckilyyg commented Jun 16, 2022 via email

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