关于内存泄露
内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。(摘自度娘)
内存泄露了
在一次项目的开发中,代码的健壮性以及重用性尤为重要;
在不健壮的代码中,会导致各种各样的bug,最常见的就是内存泄漏了。有些内存泄露是个人代码的问题,有些则是系统API带来的问题;还好我们有各种各样的内存检查工具来帮助我们。
<!--more-->
在一个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
@Override
public 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);
即可解决问题。
总结
不得不说
leakcanary
真是个好东西。平常出了问题要多思考,毕竟很多的东西的内部实现决定了外边运行环境的限制;
除了
ConnectivityManager
之外,WifiManager
context.getSystemService(Context.CAMERA_SERVICE)
等其他getSystemService() 都有类似内存泄露的情况。学会Google很重要。学会Google很重要。学会Google很重要。重要的事情要说三遍!!!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。