金鞍玉勒寻芳客,未信我庐别有春。这篇文章主要讲述(转载) Android常见的几种内存泄漏小结相关的知识,希望能为你提供帮助。
转载:
http://www.jb51.net/article/109261.htm
在android程序开发中,当一个对象已经不需要再使用了,本该被回收时,而另外一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中,内存泄漏就产生了。内存泄漏有什么影响呢?它是造成应用程序OOM的主要原因之一。由于Android系统为每个应用程序分配的内存有限,当一个应用中产生的内存泄漏比较多时,就难免会导致应用所需要的内存超过这个系统分配的内存限额,这就造成了内存溢出而导致应用Crash。了解了内存泄漏的原因及影响后,我们需要做的就是掌握常见的内存泄漏,并在以后的Android程序开发中,尽量避免它。
1、单例造成的内存泄漏
Android的单例模式非常受开发者的喜爱,不过使用的不恰当的话也会造成内存泄漏。因为单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class SingleInstance {
private static SingleInstance instance;
private Context context;
private SingleInstance(Context context) {
this .context = context;
}
public synchronized static SingleInstance getInstance(Context context) {
if (instance != null ) {
instance = new SingleInstance(context);
}
return instance;
}
} |
所以正确的单例应该为这种姿势:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class SingleInstance {
private static SingleInstance instance;
private Context context;
private SingleInstance(Context context) {
this .context = context.getApplicationContext();
}
public synchronized static SingleInstance getInstance(Context context) {
if (instance != null ) {
instance = new SingleInstance(context);
}
return instance;
}
} |
2、非静态内部类(比如内部类、匿名内部类)创建静态实例造成的内存泄漏
有的时候我们可能会在启动频繁的Activity中,为了避免重复创建相同的数据资源,会出现这种写法:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class MainActivity extends AppCompatActivity {
private InnerClass innerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (innerClass == null ){
innerClass = new InnerClass();
}
}
class InnerClass{
}
} |
正确的做法为:将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例,如果需要使用Context,请使用ApplicationContext 。
3、Handler造成的内存泄漏
Handler的使用造成的内存泄漏问题应该说最为常见了,平时在处理网络任务或者封装一些请求回调等api都应该会借助Handler来处理,对于Handler的使用代码编写一不规范即有可能造成内存泄漏,如下示例:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class MainActivity extends AppCompatActivity {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//...
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
}
private void loadData(){
//...request
Message message = Message.obtain();
mHandler.sendMessage(message);
}
} |
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | public class MainActivity extends AppCompatActivity {
private MyHandler mHandler = new MyHandler( this );
private TextView mTextView ;
private static class MyHandler extends Handler {
private WeakReference<
Context>
reference;
public MyHandler(Context context) {
reference = new WeakReference<
>
(context);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = (MainActivity) reference.get();
if (activity != null ){
activity.mTextView.setText( "" );
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.textview);
loadData();
}
private void loadData() {
//...request
Message message = Message.obtain();
mHandler.sendMessage(message);
}
} |
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | public class MainActivity extends AppCompatActivity {
private MyHandler mHandler = new MyHandler( this );
private TextView mTextView ;
private static class MyHandler extends Handler {
private WeakReference<
Context>
reference;
public MyHandler(Context context) {
reference = new WeakReference<
>
(context);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = (MainActivity) reference.get();
if (activity != null ){
activity.mTextView.setText( "" );
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.textview);
loadData();
}
//加载网络数据的回调
private void loadData() {
//...request
Message message = Message.obtain();
mHandler.sendMessage(message);
}
@Override
protected void onDestroy() {
super .onDestroy();
//移除消息队列和回调
mHandler.removeCallbacksAndMessages( null );
}
} |
当然简单点,也可以直接这样
?
1 2 3 4 5 6 | @Override
protected void onDestroy() {
super .onDestroy();
//移除消息队列和回调
mHandler.removeCallbacksAndMessages( null );
} |
4、线程造成的内存泄漏
对于线程造成的内存泄漏,也是平时比较常见的,如下这两个示例可能每个人都这样写过:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //——————test1
new AsyncTask<
Void, Void, Void>
() {
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep( 10000 );
return null ;
}
}.execute();
//——————test2
new Thread( new Runnable() {
@Override
public void run() {
SystemClock.sleep( 10000 );
}
}).start();
|
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | static class MyAsyncTask extends AsyncTask<
Void, Void, Void>
{
private WeakReference<
Context>
weakReference;
public MyAsyncTask(Context context) {
weakReference = new WeakReference<
>
(context);
}
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep( 10000 );
return null ;
}
@Override
protected void onPostExecute(Void aVoid) {
super .onPostExecute(aVoid);
MainActivity activity = (MainActivity) weakReference.get();
if (activity != null ) {
//...
}
}
}
static class MyRunnable implements Runnable{
@Override
public void run() {
SystemClock.sleep( 10000 );
}
}
//——————
new Thread( new MyRunnable()).start();
new MyAsyncTask( this ).execute();
|
5、资源未关闭造成的内存泄漏
对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。
6、WebView、或百度、高德地图的MapView引起的内存泄漏,可以参考我的这篇文章
WebView引起的内存泄漏:http://www.jb51.net/article/79372.htm
【(转载) Android常见的几种内存泄漏小结】
推荐阅读
- 让App中增加LruCache缓存,轻松解决图片过多造成的OOM
- Android Adb Analyse
- android 实现微信分享多张图片的功能
- android 6.0之后动态获取权限
- DIY平面设计软件推荐合集(10大最佳Canva替代品)
- Windows 10如何截屏(9种快速方法分步教程)
- ORACLE TRUNCATE TABLE语句
- Oracle TRUNCATE TABLE语句用法
- Oracle左外联接查询