博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Activity内部Handler引起内存泄露的原因分析
阅读量:6200 次
发布时间:2019-06-21

本文共 3645 字,大约阅读时间需要 12 分钟。

有时在Activity中使用Handler时会提示一个内存泄漏的警告,代码通常如下:

 

[java] 
 
  1. public class MainActivity extends Activity {  
  2.   
  3.     private TextView tvHelloWorld;  
  4.     private Button btnSetText;  
  5.     private Handler mHandler = new Handler();  
  6.   
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_main);  
  11.         btnSetText = (Button) findViewById(R.id.btn_set_text);  
  12.         tvHelloWorld = (TextView) findViewById(R.id.tv_hello_world);  
  13.         btnSetText.setOnClickListener(new OnClickListener() {  
  14.   
  15.             @Override  
  16.             public void onClick(View v) {  
  17.                 mHandler.post(new Runnable() {  
  18.   
  19.                     @Override  
  20.                     public void run() {  
  21.                         tvHelloWorld.setText("Runnable");  
  22.                     }  
  23.   
  24.                 });  
  25.             }  
  26.   
  27.         });  
  28.     }  
  29.   
  30. }  

Lint Warning原文如下:

This Handler class should be static or leaks might occur (com.example.testhandler.MainActivity.1)

Issue: Ensures that Handler classes do not hold on to a reference to an outer class
Id: HandlerLeak
Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.

 

1. 内存泄露原因分析

由于这个Handler作为内部类声明在Activity内部,普通的内部类对象隐式地保存了一个指向外部类对象的引用,所以这个Handler对象保存了一个指向Activity对象的引用。而这个Handler对象的生命周期可能比Activity生命周期场,比如当有一个后台线程持有该Handler,别且该线程在执行一个长时间任务。所以当该Handler没有被JVM垃圾回收器回收时,它就阻止了它引用的外部类Activity对象的回收,这里就导致了内存泄露。

2. 如何解决这种内存泄露问题

在该内存泄露的Lint Warning中给出了解决该问题的方法。将Handler类声明为静态内部类,即解除内部类对象与其外部类对象之间的联系。创建一个外部类的WeakReference,并在实例化Handler对象时使用它。代码实现如下:

 

[java] 
 
  1. public class MainActivity extends Activity {  
  2.   
  3.     private TextView tvHelloWorld;  
  4.     private Button btnSetText;  
  5.     private Handler mHandler = new InternalHandler(this);  
  6.   
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_main);  
  11.         btnSetText = (Button) findViewById(R.id.btn_set_text);  
  12.         tvHelloWorld = (TextView) findViewById(R.id.tv_hello_world);  
  13.         btnSetText.setOnClickListener(new OnClickListener() {  
  14.   
  15.             @Override  
  16.             public void onClick(View v) {  
  17.                 mHandler.post(new Runnable() {  
  18.   
  19.                     @Override  
  20.                     public void run() {  
  21.                         tvHelloWorld.setText("Runnable");  
  22.                     }  
  23.   
  24.                 });  
  25.             }  
  26.   
  27.         });  
  28.     }  
  29.   
  30.     private static class InternalHandler extends Handler {  
  31.         private WeakReference<Activity> weakRefActivity;  
  32.   
  33.         /** 
  34.          * A constructor that gets a weak reference to the enclosing class. We 
  35.          * do this to avoid memory leaks during Java Garbage Collection. 
  36.          */  
  37.         public InternalHandler(Activity activity) {  
  38.             weakRefActivity = new WeakReference<Activity>(activity);  
  39.         }  
  40.   
  41.         @Override  
  42.         public void handleMessage(Message msg) {  
  43.             Activity activity = weakRefActivity.get();  
  44.             if (activity != null) {  
  45.   
  46.             }  
  47.         }  
  48.     }  
  49. }  

3. SoftReference、WeakReference和PhantomReference

 

SoftReference、WeakReference和PhantomReference是java.lang.ref类库中的一组类。当垃圾回收器正在考察的对象只能通过某个Reference对象才“可获得”时,这3个类为垃圾回收器提供了不同级别的间接性提示。

对象是可获得的(reachable),是指此对象可在程序中的某处找到。这意味着你在栈中有一个普通的“引用A”,而它正指向此“对象A”,也可能是“引用B”指向“对象B”,而“对象B”含有“引用C”指向“对象A”,也可能是更多的中间链接。如果一个对象是“可获得的”,垃圾回收器就不能释放它,因为它仍然为你的程序所用。如果一个对象不是“可获得的”,那么你的程序将无法使用到它,所以将其回收是安全的。

如果想继续持有某个对象的引用,想以后还能够访问到该对象,同时也想在内存消耗殆尽的时候垃圾回收器回收它,这时就应该使用Reference对象。

SoftReference、WeakReference和PhantomReference由强到弱排列,表示不同级别的“可获得性”。

SoftReference用以实现内存敏感的高速缓存。

WeakReference是为实现“规范映射”(canonicalizing mappings)而设计的,它不妨碍垃圾回收器回收映射的“键”(或“值”)。“规范映射”中对象的实例可以在程序的多处被同时使用,以节省存储空间。

PhantomReference用以调度回收前的清理工作,它比Java终止机制更加灵活。

转载地址:http://rytca.baihongyu.com/

你可能感兴趣的文章
Win10系统删除通知栏已经卸载了的软件的图标
查看>>
Nginx配置(nginx.conf)详解
查看>>
异常抛出增强使用方法及案例
查看>>
MyBatis的接口层(一)
查看>>
一体化建模仿真平台20-sim v4.6.3发布丨附下载
查看>>
Visual Studio 2017 v15.5预览版的新特性先睹为快
查看>>
干货!9种高性能可用高并发的技术架构
查看>>
Elasticsearch PHP MYSQL的同步使用
查看>>
关于生成二维码导致显示不出来 vivo手机出现问题解决办法
查看>>
模拟光链路 动态范围
查看>>
20天时间,一个人怎么搞定这个后台管理项目
查看>>
go并发基础数据加锁解锁
查看>>
6-SpringIOC原理
查看>>
北大教授邱泽奇:农村电商,为什么是菏泽?
查看>>
黄仁勋打响CES第一枪:全球最强芯DRIVE Xavier武装自动驾驶
查看>>
Tengine TLSv1.3最佳实践
查看>>
利用redis缓存对 list集合中的数据 进行分页操作
查看>>
云效(原RDC)如何构建一个基于Maven的Java项目
查看>>
RabbitMQ消息反序列化失败问题回顾
查看>>
Oracle 中实现查找树形结构节点功能
查看>>