Android内存泄漏的原因及解决技巧

正确的生命周期管理如何防止Android内存泄漏

OutOfMemoryException是一个常见的令人沮丧的错误,也是导致应用程序意外关闭的主要原因之一。

“如果应用程序昨天运行良好,为什么现在会发生这种情况?这个问题让Android的开发者和新手都感到困惑。

导致OutOfMemory异常的潜在原因有很多种,但其中最常见的是内存泄漏—应用程序中的内存分配从未释放。本文将解释如何通过有效的生命周期管理(开发过程中一个重要但经常被忽视的部分)来最小化这种风险。

为什么安卓系统会发生内存泄漏?

问题很简单。某些对象应该只有一个固定的寿命,当它们的使用寿命结束时,它们需要被删除。

理论上,当进程使用onStop或onDestroy终止时,应该处理该内存。但是,滥用对象引用可能会阻止垃圾收集器释放未使用的对象。例如:如果未使用的对象A引用了未使用的对象B,那么您将得到两个不必要的对象,垃圾回收器将永远不会释放它们,因为它们正在相互引用。

阻止内存泄漏这种情况发生的常见技巧

开发人员可以采取许多步骤来阻止死的活动被困在内存中。

  1. 在onResume()/onPause()或onStart()/onStop()中注册/注销广播接收器
  2. 不要对视图/活动/上下文使用静态变量
  3. 需要保存对上下文的引用的singleton应该使用applicationContext()或将其包装到WeakReference中
  4. 注意匿名和非静态内部类,因为它们包含对其封闭类的隐式引用。
  5. 如果要比父类(如处理程序)更长寿,请使用静态内部类而不是匿名类。
  6. 如果内部或匿名类是可取消的(如AsyncTask、Thread、RxSubscriptions),则在销毁活动时取消它。

Android生命周期感知组件

一旦你完成了上面的基本步骤,现在是时候做一些更重要的事情了:应用程序活动的生命周期。如果我们不能正确地管理生命周期,我们最终会在不再需要内存的时候挂掉它。

这涉及到许多不同的任务。对于每个活动,我们需要中断线程,去掉RxJava中的订阅,取消AsyncTask引用,并确保正确删除该活动的引用(以及与之相关的任何其他活动)。所有这些任务都会消耗开发人员的大量时间。

模型视图呈现器(MVP)使事情变得更加复杂,MVP是Android中构建用户界面的常用架构模式。然而,MVP对于从视图中分离业务逻辑非常有用。

在MVP模式中,View和Presenter都是它们之间行为契约的抽象实现。实现MVP最常见的方法是使用活动/片段作为视图的实现,并为习惯于引用视图的演示者使用简单的实现。

所以我们最终得到了一个带有Presenter引用的视图和一个带有视图引用的Presenter(提示:这里有一个潜在的漏洞)。

考虑到这些潜在的困难,我们有必要建立一个适当的管理结构来移除在生命周期中创建的多余内存。有几种行之有效的方法可以做到这一点:

1. 在Android Studio上使用Android Arch Lifecycle创建支持生命周期的组件

生命周期感知组件是智能的。例如,它们可以通过除去内存来对另一个组件(如活动或片段)的生命周期状态的更改作出反应。这意味着代码更轻,内存效率更高。

archlifecycle是Android的一个新库,它提供了一组工具来构建支持生命周期的组件。库以抽象的方式工作,这意味着生命周期所有者不再需要担心管理特定任务和活动的生命周期。

Arch生命周期的关键工具和定义如下:

  • 生命周期:一个排序系统,它定义了哪些对象具有Android生命周期,并允许对它们进行监视。
  • LifecycleObserver:一个常规接口,它监视每个被标识为具有Android生命周期的对象,使用一个简单的公式来处理每个密钥生命周期事件。
  • @OnLifecycleEvent:可以在实现LifecycleObserver接口的类中使用的注释。它允许我们设置关键生命周期事件,这些事件将在每次启动时触发带注释的方法。以下是可设置的所有事件的列表:ON_ANY、ON_CREATE、ON_DESTROY、ON_PAUSE、ON_RESUME、ON_START、ON_STOP
  • LifecycleOwner默认为每个可以管理其生命周期的Android组件实现,并让开发人员控制每个事件。

使用这些工具,我们可以将所有干净的任务发送给它们的所有者(在我们的例子中是演示者),这样我们就有了一个干净的、无泄漏的解耦代码(至少在演示者层是这样)。

下面是一个超级基本的实现,向您展示我们所说的:

interface View: MVPView, LifecycleOwner

class RandomPresenter : Presenter<View>, LifecycleObserver {
 private lateinit var view: View
 override fun attachView(view: View) {
  this.view = view
  view.lifecycle.addObserver(this)
 }

 @OnLifecycleEvent(Lifecycle.Event.On_DESTROY)
 fun onClear() {
	//TODO: clean
}

2. 使用Android架构视图模型作为演示者和LiveData

另一种方法是通过使用新的生命周期组件来避免视图模型的内存泄漏。

ViewModel是一个抽象类,它实现一个称为onClear的函数,当必须删除某个特定对象时,该函数会自动调用。ViewModel是由框架生成的,它附加到创建者的生命周期中(作为一个额外的好处,使用Dagger注入非常容易)

除了使用ViewModel,LiveData还提供了一个重要的通信渠道。这意味着创造了一个容易观察到的反应性产物。

这里最重要的一点是,生命周期所有者可以观察到LiveData,因此数据传输总是由生命周期管理的,而且我们可以确保在使用它们时保留任何引用。

3. 使用LeakCanary和Bugfender

除了上述步骤之外,我们还想推荐两个重要的工具包:LeakCanary,一个用于监视泄漏的流行工具,以及我们自己的Bugfender。

LeakCanary是一个用于Android和Java的内存检测库。它是开源的,所以有一个庞大的社区支持它,它不仅仅告诉你一个漏洞,它还告诉你可能的原因。

我们的远程日志工具Bugfender允许您调试单个泄漏跟踪,并扩展一个名为DisplayLeakService的类,它让我们知道何时发生泄漏。然后我们就可以用Bugfender轻松登录了。

public class LeakUploadService extends DisplayLeakService {
 override fun afterDefaultHandling(heapDump: HeapDump, result: AnalysisResult, leakInfo: String) {
  if (result.leakFound) {
   Bugfender.d(“LeakCanary”, result.toString())
  }
 }
}

此外,用户还可以获得Bugfender的所有其他好处,包括全天候记录日志(即使设备离线)、内置故障报告和易于使用的web控制台。

以上就是Android内存泄漏的原因及解决技巧的详细内容,更多关于Android内存泄漏的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解Android内存泄漏检测与MAT使用

    内存泄漏基本概念 内存检测这部分,相关的知识有JVM虚拟机垃圾收集机制,类加载机制,内存模型等.编写没有内存泄漏的程序,对提高程序稳定性,提高用户体验具有重要的意义.因此,学习Java利用java编写程序的时候,要特别注意内存泄漏相关的问题.虽然JVM提供了自动垃圾回收机制,但是还是有很多情况会导致内存泄漏. 内存泄漏主要原因就是一个生命周期长的对象,持有了一个生命周期短的对象的引用.这样,会导致短的对象在该回收时候无法被回收.Android中比较典型的有:1.静态变量持有Activity的co

  • Android Native 内存泄漏系统化解决方案

    导读:C++内存泄漏问题的分析.定位一直是Android平台上困扰开发人员的难题.因为地图渲染.导航等核心功能对性能要求很高,高德地图APP中存在大量的C++代码.解决这个问题对于产品质量尤为重要和关键,高德地图技术团队在实践中形成了一套自己的解决方案. 分析和定位内存泄漏问题的核心在于分配函数的统计和栈回溯.如果只知道内存分配点不知道调用栈会使问题变得格外复杂,增加解决成本,因此两者缺一不可. Android中Bionic的malloc_debug模块对内存分配函数的监控及统计是比较完善的,但

  • Android Handler内存泄漏详解及其解决方案

    关联篇:深入Android的消息机制源码详解-Handler,MessageQueue与Looper关系 关联篇:HandlerThread 使用及其源码完全解析 在android开发过程中,我们可能会遇到过令人奔溃的OOM异常,面对这样的异常我们是既熟悉又深恶痛绝的,因为造成OOM的原因有很多种情况,如加载图片过大,某已不再使用的类未被GC及时回收等等......本篇我们就来分析其中一种造成OOM的场景,它就是罪恶的内存泄漏.对于这样的称呼,我们并不陌生,甚至屡次与之"并肩作战",

  • Android性能优化之利用Rxlifecycle解决RxJava内存泄漏详解

    前言: 其实RxJava引起的内存泄漏是我无意中发现了,本来是想了解Retrofit与RxJava相结合中是如何通过适配器模式解决的,结果却发现了RxJava是会引起内存泄漏的,所有想着查找一下资料学习一下如何解决RxJava引起的内存泄漏,就查到了利用Rxlifecycle开源框架可以解决,今天周末就来学习一下如何使用Rxlifecycle. 引用泄漏的背景: RxJava作为一种响应式编程框架,是目前编程界网红,可谓是家喻户晓,其简洁的编码风格.易用易读的链式方法调用.强大的异步支持等使得R

  • Android 内存溢出和内存泄漏的问题

    Android 内存溢出和内存泄漏的问题 在面试中,经常有面试官会问"你知道什么是内存溢出?什么是内存泄漏?怎么避免?"通过这篇文章,你可以回答出来了. 内存溢出 (OOM)是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory:比如只申请了一个integer,但给它存了long才能存下的数,那就会出现内存溢出. 内存泄露 (memory leak)是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存

  • Android内存泄漏的轻松解决方法

    前言 内存管理的目的就是让我们在开发过程中有效避免我们的应用程序出现内存泄露的问题.内存泄露相信大家都不陌生,我们可以这样理解:「没有用的对象无法回收的现象就是内存泄露」. 如果程序发生了内存泄露,则会带来以下这些问题 应用可用的内存减少,增加了堆内存的压力 降低了应用的性能,比如会触发更频繁的 GC 严重的时候可能会导致内存溢出错误,即 OOM Error 下面我们从基础说起 基础知识 Java 的内存分配简述 方法区(non-heap):编译时就分配好,在程序整个运行期间都存在.它主要存放静

  • Android中内存泄漏需要的注意点

    内存泄漏对每一位 Android 开发一定是司空见惯,大家或多或少都肯定有些许接触.大家都知道,每一个手机都有一定的承载上限,多处的内存泄漏堆积一定会堆积如山,最终出现内存爆炸 OOM. 而这,也是极有可能在 Android 面试中一道常见的开放题. 内存泄漏的根本原因是一个长生命周期的对象持有了一个短生命周期的对象.如果你对垃圾回收机制有所了解,我想这个问题基本难不住你,因为知道了原理,自然不会去触碰这些极易导致内存泄漏的雷区. 该题重在积累,不需要死记硬背,自己多总结即可. 1. 长生命周期

  • Android 5.1 WebView内存泄漏问题及快速解决方法

    问题背景 在排查项目内存泄漏过程中发现了一些由WebView引起的内存泄漏,经过测试发现该部分泄漏只会出现在android 5.1及以上的机型.虽然项目使用WebView的场景并不多,但秉承着一个泄漏都不放过的精神,我们肯定要把它给解决了. 遇到的问题 项目中使用WebView的页面主要在FAQ页面,问题也出现在多次进入退出时,发现内存占用大,GC频繁.使用LeakCanary观察发现有两个内存泄漏很频繁: 我们分析一下这两个泄漏: 从图一我们可以发现是WebView的ContentViewCo

  • Android内存溢出及内存泄漏原因进行

    内存溢出(Out Of Memory):Android系统中每一个应用程序可以向系统申请一定的内存,当申请的内存不够用的时候,就产生了内存溢出. 内存泄漏:当某个对象不再被使用,即不再有变量引用它时,该对象占用的内存就会被系统回收.当某个对象不再被使用,但是在其他对象中仍然有变量引用它时,该对象占用的内存就无法被系统回收,从而导致了内存泄漏. 当内存泄漏过多时,可用内存空间会减少,应用程序申请的内存不够用,就会导致内存溢出. 内存溢出原因: 1.内存泄漏过多. 2.内存中加载的数据量超过内存的可

  • Android Studio 3.0上分析内存泄漏的原因

    以前用eclipse的时候,我们采用的是DDMS和MAT,不仅使用步骤复杂繁琐,而且要手动排查内存泄漏的位置,操作起来比较麻烦.后来随着Android studio的潮流,我也抛弃了eclipse加入了AS. Android Studio也开始支持自动进行内存泄漏检查,并且操作起来也比较方便. 封面 戳我下载 Android Studio 3.0 这个不用梯子我会告诉你吗 1.写在前面 Google在上周发布了Android Studio 3.0的正式版本,周四早晨在上班的地铁上就看到群里在沸沸

随机推荐