关于内存泄露

内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。(摘自度娘)

内存泄露了

在一次项目的开发中,代码的健壮性以及重用性尤为重要;
在不健壮的代码中,会导致各种各样的bug,最常见的就是内存泄漏了。有些内存泄露是个人代码的问题,有些则是系统API带来的问题;还好我们有各种各样的内存检查工具来帮助我们。

在一个Android项目中,要使用到一个常用的判断网络状态的功能;

代码:

public static boolean isNetWorkConnected(Context context) {        ConnectivityManager cm = (ConnectivityManager) context                .getSystemService(Context.CONNECTIVITY_SERVICE);        NetworkInfo netInfo = cm.getActiveNetworkInfo();        return netInfo != null && netInfo.isConnected();    }...public class MainActivity extends BaseActivity {     ...        if(isNetWorkConnected(MainActivity.this)){            ... todo:  Network Fine        }else{            ... todo: No Network        }     ...}

代码并不难理解,可以使用了LeakCanary检查之后 发现了内存泄露;

* GC ROOT static android.net.ConnectivityManager.sInstance* references android.net.ConnectivityManager.mContext* leaks top.itmp.jiandan.ui.MainActivity instance

看着很明显了, 最终问题 出在ConnectivityManager上,Google之后发现,
github上有些类似的bug: Memory leak in WiFiManager from Android SDK

看来是Android getSystemService()的实现中的问题;

部分Android源码实现如下:

//ContextImpl.java@Overridepublic Object getSystemService(String name) {    ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);    return fetcher == null ? null : fetcher.getService(this);} static {    registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {            public Object getService(ContextImpl ctx) {            return AccessibilityManager.getInstance(ctx);            }});     registerService(CAPTIONING_SERVICE, new ServiceFetcher() {            public Object getService(ContextImpl ctx) {            return new CaptioningManager(ctx);            }});     registerService(ACCOUNT_SERVICE, new ServiceFetcher() {            public Object createService(ContextImpl ctx) {            IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);            IAccountManager service = IAccountManager.Stub.asInterface(b);            return new AccountManager(ctx, service);            }});    // ... ...}

解决办法

所已在Android开发中, 了解甚至熟悉Android系统的源码实现还是很重要的;毕竟还是开源的好。

解决办法: 使用Application Context 替换 Activity context 即可;

 if(isNetWorkConnected(getApplicationContext())){    ...}

或者:

ConnectivityManager cm = (ConnectivityManager) getApplicationContext()                .getSystemService(Context.CONNECTIVITY_SERVICE);

即可解决问题。

总结

  1. 不得不说 leakcanary 真是个好东西。

  2. 平常出了问题要多思考,毕竟很多的东西的内部实现决定了外边运行环境的限制;

  3. 除了ConnectivityManager之外, WifiManager context.getSystemService(Context.CAMERA_SERVICE)等其他getSystemService() 都有类似内存泄露的情况。

  4. 学会Google很重要。学会Google很重要。学会Google很重要。重要的事情要说三遍!!!

更多相关文章

  1. 使用vs2010查看android原生代码
  2. Android(安卓)DOM方式解析XML文件
  3. 分享开发 Android(安卓)手机应用的开发经验——QR生成器
  4. 在Android系统使用socket在Java层和native之间数据通信
  5. Android(安卓)内置群组,联系人
  6. android -- sim/usim卡导联系人
  7. Android定时任务的应用及实现
  8. Android(安卓)为例编写一个 OpenGL ES 3.0 实例,Native & Java 两
  9. Android(安卓)热修复以及阿里AndFix方案使用

随机推荐

  1. 从零开始--系统深入学习android(实践-让我
  2. 个人使用的Android(安卓)Studio快捷键(MAC
  3. 在android中使用proguard混淆代码出现“C
  4. Android中的脑残设计
  5. Android(安卓)drawable微技巧,你所不知道
  6. Android(安卓)如何进入Android工程模式
  7. IPv6升级测试指南(Android/iOS/Mac)
  8. Android(安卓)来电(包括铃声),短信拦截的
  9. Android中I/O
  10. android接口调试工具