zoukankan      html  css  js  c++  java
  • android : Avoiding Memory Leaks

      本文是articles里面的第一篇文章,其实老早就注意到这个问题,由于刚开始的时候没有看懂,今天重新看了下,印象还是满深刻的:它就是错误使用context导致内存泄露。

      android系统的应用程序(至少T-Mobile G1)被限制16M堆大小范围内。设备拥有很多的内存但是开发者想要得到却很少。即使你不想使用设备所有的内存,你也应该在不杀死其他应用程序的情况下使用最少(的内存)。越多的程序在内存中,用户切换程序的速度就越快。在我的一部分工作中,我遇到一些内存问题他们大部分都源于一个错误:保持长时间引用Context(简单说就是Context泄露)。

      android系统里,Context被常用来加在和使用资源。这也是为什么很多Widget在够找函数中接受一个Context的参数了。在一个通常的android应用里,你经常可以使用两个Context(Activity和Application)。开发者通常会传递Context参数到一个类和一个方法中:

    1 @Override
    2 protected void onCreate(Bundle state) {
    3 super.onCreate(state);
    4
    5 TextView label = new TextView(this);
    6 label.setText("Leaks are bad");
    7
    8 setContentView(label);
    9 }

      把activity的context传递给view,意味着view拥有一个整个activity的引用,进而引用activity占有的任何资源:通常整个View结构和所有的资源。因此,如果 context发生内存泄露的话,就会泄露很多内存。如果你不小心,你很容易泄露整个Activity。

      当屏幕方法方向发生改变的时候,默认情况下,会销毁当前的activity接着创建一个新的。那么,android系统会重新加在应用的UI和资源。比如在一个应用里,你不想每次旋转的时候重新加在一张大的图片,那么最简单的方式就是把它设置为静态变量:

     1 private static Drawable sBackground;
    2
    3 @Override
    4 protected void onCreate(Bundle state) {
    5 super.onCreate(state);
    6
    7 TextView label = new TextView(this);
    8 label.setText("Leaks are bad");
    9
    10 if (sBackground == null) {
    11 sBackground = getDrawable(R.drawable.large_bitmap);
    12 }
    13 label.setBackgroundDrawable(sBackground);
    14
    15 setContentView(label);
    16 }

      上述代码十分错误。当第一个屏幕方向发生改变的时候,他会泄露第一个activity。当把图片附在一个View的时候,Drawable的回掉函数callback()引用View(事实上在setBackgroundDrawable函数里,发生sBackgroud.setCallBack(label))。在整个代码片段里面,这个drawable对象用户一个包含activity对象引用的TextView的引用。

      这个范例是一个最简单泄露Context的例子,你可以去Home screen's source code代码里面看看:当activity被销毁的时候,设置被存储drawable的callbacks为null.很有趣的是,许多你创建了一个链式的被泄露的Context是十分糟糕的。他们让你相当快的消耗内存。

      有两种方式可以避免Context相关的内存泄露。最常用的一种做法就是避免在范围外引用context.上面的例子就是显示了错误例子。第二个解决办法就是使用Application 的Context。这个Context的生命周期跟你的应用的生命周期一样长,并且不依赖于activities的生命周期。如果你需要Context来保存一个生命周期长的对象,记住使用application 的 context.你可以轻松使用Context.getApplicationContext()或者Activity.getApplication()来得到。

      总的来说,要避免Context相关的内存泄露,记住一下几点:

      1.不要让生命周期长的对象引用activity 的context。(activity的引用应该和它本身有一样的生命周期)

      2.尽量使用application-context代替activity-context

      3.如果你不能控制他们的生命周期,避免使用高非静态内部类。使用静态内部类,并在activity对它们弱引用。因为非静态内部类的对象实例化时候默认包含了它的外部类的引用。

      4.你的垃圾回收机制是否对内存泄露做了处理。(这点通常不考虑)


  • 相关阅读:
    《Robust Sparse Coding for Face Recognition》
    安装robotframwork 报错Requirement already satisfied
    python -m pip install --upgrade pip 解决升级不成功问题
    pycharm 导入requests库踩坑帖
    新电脑软件安装及环境变量配置
    monkey参数命令
    adb 命令合集
    【转载】解决Sublime编译Python时出现Decode error
    [转载]Python3 接口自动化测试项目实战一(WEB项目)
    python sublime run快捷键设置
  • 原文地址:https://www.cnblogs.com/slider/p/2277396.html
Copyright © 2011-2022 走看看