清华主页 - 清华新闻 - 综合时讯 - 正文

Android内存优化指南:从数据结构到5R规则的综合策略

目录。

一、APP 内存限制。

内存的三个主要问题。

2.1、内存抖动(Memory Churn)。

2.1.1 短生命周期对象的频繁创建。

2.1.2 不合理使用系统API或第三方库。

2.1.3 Handler使用不当。

2.2、内存泄漏(Memory Leak)。

2.2.1 Activity或Context引用静态变量。

2.2.2 未取消的回调或监听器。

2.2.3 非静态内部类持有外部类引用。

2.2.4 未正确取消Timer或Handler。

2.2.5 Bitmap没有及时回收。

2.2.6 未关闭资源文件。

2.2.7 WebView。

2.3、内存溢出(OutOfMemoryError)。

2.3.1 在为对象分配内存时,达到过程的内存上限。

2.3.2 没有足够大小的连续地址空间。

2.3.3 创建线程失败。

2.3.4 积累内存泄漏。

2.3.5 集合物未及时清理。

三、内存问题解决方案。

3.1 选择合适的数据结构。

3.2 避免使用枚举。

3.3 谨慎使用多个过程。

3.4 谨慎使用 Large Head。

3.5 使用NDK。

四、 图片优化。

4.1 如何缓存图片?

4.2 计算图片占用内存的大小。

4.3 如何计算图片占用内存的大小?

4.4 图片内存体积优化总结。

五、内存优化5R法则。

相关推荐。


一、APP 内存限制。

        Android。 给每个。 App。分配一个。 VM ,让App运行。 dalvik。就这样吧。 App。崩溃不会影响系统。系统给。 VM。分配一定的内存大小,App。即使物理内存过剩,也可以申请使用的内存大小不能超过这种硬性逻辑限制,如果应用程序超过。 VM。最大内存会溢出内存 crash。

        由程序控制的内存空间  heap。上,分。 java heapsize。和。 native heapsize。。

        Java申请的内存在于Java vm heap 上,所以如果 java 申请的内存大小。超过 VM 逻辑内存限制。,会出现内存溢出异常。(如:-Xmx4096)。

        native 层内存申请不受其限制。,native 层受。 native process。限制内存大小。

        Android 虚拟机申请的最大内存是有限的,不同设备申请的最大内存是不同的。

二、内存三大问题。

        1、内存抖动:内存波动图表呈现 锯齿张,GC导致卡顿。

        2、内存泄漏:GC在当前应用周期中不再使用的对象 引用Roots,导致无法回收,使实际可用内存变小。

        3、内存溢出:即OOM,OOM会导致程序异常。Android设备出厂后,确定了虚拟机对单个应用程序的最大内存分配,超过此值将OOM。

2.1、内存抖动(Memory Churn)。

        内存抖动是指。内存的频繁分布和回收导致内存曲线呈锯齿状波动。,可能。导致应用页面卡顿或响应缓慢。。常见的内存抖动场景和解决方案。:。

2.1.1 短生命周期对象的频繁创建。

        循环或频繁调用的方法。创建大量短生命周期的对象。,如字符串拼接、对象创建频繁等。

        定制控制。件的。onMeasure。、。onLayout。、。onDraw。在其他方法中创建对象。,由于这些方法被频繁地调用,对象被频繁地创建和回收。

解决方案。

  • 避免在循环或频繁调用的方法中创建对象。
  • 使用StringBuilder等高效字符串拼接来代替加号拼接。
  • 在自定义控件的绘制方法中,尽量重用对象,避免频繁创建。
  • 对于需要频繁创建和销毁的对象,可以考虑使用对象池来重用对象。对象池可以减少对象的创建和销毁,从而降低内存抖动的可能性。

2.1.2 不合理使用系统API或第三方库。

        在调用系统API或第三方库时,没有合理使用其提供的对象重用机制,导致大量对象被创建。

解决方案。

  • 深入了解系统API和第三方库的工作原理,合理利用其提供的对象重用机制。
  • 避免创建不必要的对象,如使用。Message.obtain()。获取Message对象的方法,而不是直接创建新的Message对象。

2.1.3 Handler使用不当。

        Handler发送大量消息,消息处理不及时,导致消息对象积累。

解决方案。

  • 在Handler中处理消息时,确保及时处理和释放消息对象。
  • 对于延迟消息,在Activity或View生命周期结束前取消未处理的消息。
  • 队列优化=>重复新闻过滤。
  • 队列优化=>互斥消息被取消。
  • 复用新闻,使用。Message.obtain()。获取Message对象的方法。
  • 使用新闻空闲ldleHandle。

2.2、内存泄漏(Memory Leak)。

        内存泄漏是指。长生命周期的对象持有短生命周期对象的引用。,当不再需要时,应用程序中的对象仍然被引用,导致垃圾回收器(Garbage Collector,GC)。这些对象所占用的内存无法回收。。内存泄漏会导致可用内存逐渐减少,最终可能。导致应用程序崩溃(OOM)或者系统变得非常缓慢。。常见的内存泄漏场景及解决方案:

2.2.1 Activity或Context引用静态变量。

        Activity或Context在静态变量中持有强引用。当Activity或Context不再需要时,这些对象无法回收,因为静态变量的生命周期与应用程序相同。

解决方案。

  • 避免在静态变量中持有Activity或Context的强引用。
  • 如果您确实需要持有Context,请考虑使用aplication Context或弱引用(WeakReference)。

2.2.2 未取消的回调或监听器。

        回调或监听器在Activity或Fragment中注册,但在适当的生命周期方法中未取消注册,导致Activity或Fragment被销毁后,回调或监听器仍持有其引用。

解决方案。

  • 取消Activity或Fragmentondestroy或ondetach方法中的所有回调和监听器注册。
  • 使用View观察者模式时,确保View不再需要时解除观察。

2.2.3 非静态内部类持有外部类引用。

        默认情况下,非静态内部类持有其外部类的参考。如果非静态内部类长期持有(如作为静态变量成员),则外部类不能回收。

解决方案。

  • 将内部类声明为静态内部类,并通过结构方法传递必要的Context或其他引用。
  • 如果内部类需要访问外部类成员,考虑使用弱引用持有外部类的引用。

2.2.4 未正确取消Timer或Handler。

        使用Timer或Handler时,如果定时任务或消息没有正确取消,这些定时任务或消息在Activity或Fragment销毁后仍可能被引用。

解决方案。

  • 取消Activity或Fragmentondestroy或ondetach方法中的所有timer任务。
  • 对于Handler,确保在Activity或View生命周期结束前处理所有信息,并调用Handler.removeCallbacksAndMessages(null)取消所有回调和消息。

2.2.5 Bitmap没有及时回收。

        如果Bitmap对象在加载大图片或处理图片时没有及时回收,可能会导致内存泄漏。

解决方案。

  • 不再需要Bitmap时,及时调用Bitmap.recycle()回收Bitmap的方法。
  • 使用图片加载库(如Glidee)、Picasso)在Activity或Fragment销毁后,这些库通常会自动管理Bitmap的回收,但仍需注意避免继续加载图片。

2.2.6 未关闭资源文件。

        如果这些资源在处理文件、数据库连接等资源时没有正确关闭,也可能导致内存泄露。

2025-06-24 12:05:53

相关新闻

清华大学新闻中心版权所有,清华大学新闻网编辑部维护,电子信箱: news@tsinghua.edu.cn
Copyright 2001-2020 news.tsinghua.edu.cn. All rights reserved.