android handlerandroid 内存泄漏漏怎么检测

比特客户端
您的位置:
详解大数据
详解大数据
详解大数据
详解大数据
Android内存泄漏的八种可能
关键字:内存
  Java是垃圾回收语言的一种,其优点是开发者无需特意管理内存分配,降低了应用由于局部故障(segmentation fault)导致崩溃,同时防止未释放的内存把堆栈(heap)挤爆的可能,所以写出来的代码更为安全。
  不幸的是,在Java中仍存在很多容易导致内存泄漏的逻辑可能(logical leak)。如果不小心,你的应用很容易浪费掉未释放的内存,最终导致内存用光的错误抛出(out-of-memory,OOM)。
  一般内存泄漏(traditional memory leak)的原因是:当该对象的所有引用都已经释放了,对象仍未被释放。(译者注:Cursor忘记关闭等)
  逻辑内存泄漏(logical memory leak)的原因是:当应用不再需要这个对象,当仍未释放该对象的所有引用。
  如果持有对象的强引用,垃圾回收器是无法在内存中回收这个对象。
  在Android开发中,最容易引发的内存泄漏问题的是Context。比如Activity的Context,就包含大量的内存引用,例如View Hierarchies和其他资源。一旦泄漏了Context,也意味泄漏它指向的所有对象。Android机器内存有限,太多的内存泄漏容易导致OOM。
  检测逻辑内存泄漏需要主观判断,特别是对象的生命周期并不清晰。幸运的是,Activity有着明确的生命周期,很容易发现泄漏的原因。Activity.onDestroy()被视为Activity生命的结束,程序上来看,它应该被销毁了,或者需要回收这些内存(译者注:当内存不够时,Android会回收看不见的Activity)。
  如果这个方法执行完,在堆栈中仍存在持有该Activity的强引用,垃圾回收器就无法把它标记成已回收的内存,而我们本来目的就是要回收它!
  结果就是Activity存活在它的生命周期之外。
  Activity是级对象,应该让Android系统来处理它。然而,逻辑内存泄漏总是在不经意间发生。(译者注:曾经试过一个Activity导致20M内存泄漏)。在Android中,导致潜在内存泄漏的陷阱不外乎两种:
  全局进程(process-global)的static变量。这个无视应用的状态,持有Activity的强引用的怪物。
  活在Activity生命周期之外的线程。没有清空对Activity的强引用。
  检查一下你有没有遇到下列的情况。
  Static Activities
  在类中定义了静态Activity变量,把当前运行的Activity实例赋值于这个静态变量。
  如果这个静态变量在Activity生命周期结束后没有清空,就导致内存泄漏。因为static变量是贯穿这个应用的生命周期的,所以被泄漏的Activity就会一直存在于应用的进程中,不会被垃圾回收器回收。
  static A void setStaticActivity() { activity = } View saButton = findViewById(R.id.sa_button); saButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setStaticActivity(); nextActivity(); } });
  Memory Leak 1 - Static Activity
  Static Views
  类似的情况会发生在单例模式中,如果Activity经常被用到,那么在内存中保存一个实例是很实用的。正如之前所述,强制延长Activity的生命周期是相当危险而且不必要的,无论如何都不能这样做。
  特殊情况:如果一个View初始化耗费大量资源,而且在一个Activity生命周期内保持不变,那可以把它变成static,加载到树上(View Hierachy),像这样,当Activity被销毁时,应当释放资源。(译者注:示例代码中并没有释放内存,把这个static view置null即可,但是还是不建议用这个static view的方法)
   void setStaticView() { view = findViewById(R.id.sv_button); } View svButton = findViewById(R.id.sv_button); svButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setStaticView(); nextActivity(); } });
  Memory Leak 2 - Static View
  Inner Classes
  继续,假设Activity中有个内部类,这样做可以提高可读性和性。将如我们创建一个内部类,而且持有一个静态变量的引用,恭喜,内存泄漏就离你不远了(译者注:销毁的时候置空,嗯)。
  private static O void createInnerClass() { class InnerClass { } inner = new InnerClass(); } View icButton = findViewById(R.id.ic_button); icButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { createInnerClass(); nextActivity(); } });
  Memory Leak 3 - Inner Class
  内部类的优势之一就是可以访问外部类,不幸的是,导致内存泄漏的原因,就是内部类持有外部类实例的强引用。
  Anonymous Classes
  相似地,匿名类也维护了外部类的引用。所以内存泄漏很容易发生,当你在Activity中定义了匿名的AsyncTsk
  。当异步任务在后台执行耗时任务期间,Activity不幸被销毁了(译者注:用户退出,系统回收),这个被AsyncTask持有的Activity实例就不会被垃圾回收器回收,直到异步任务结束。
  void startAsyncTask() { new AsyncTask() { @Override protected Void doInBackground(Void... params) { while(true); } }.execute(); } super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); View aicButton = findViewById(R.id.at_button); aicButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startAsyncTask(); nextActivity(); } });
  Memory Leak 4 - AsyncTask
  Handler
  同样道理,定义匿名的Runnable,用匿名类Handler执行。Runnable内部类会持有外部类的隐式引用,被传递到Handler的消息队列MessageQueue中,在Message消息没有被处理之前,Activity实例不会被销毁了,于是导致内存泄漏。
  void createHandler() { new Handler() { @Override public void handleMessage(Message message) { super.handleMessage(message); } }.postDelayed(new Runnable() { @Override public void run() { while(true); } }, Long.MAX_VALUE && 1); } View hButton = findViewById(R.id.h_button); hButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { createHandler(); nextActivity(); } });
  Memory Leak 5 - Handler
  Threads
  我们再次通过Thread和TimerTask来展现内存泄漏。
  void spawnThread() { new Thread() { @Override public void run() { while(true); } }.start(); } View tButton = findViewById(R.id.t_button); tButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { spawnThread(); nextActivity(); } });
  Memory Leak 6 - Thread
  TimerTask
  只要是匿名类的实例,不管是不是在工作线程,都会持有Activity的引用,导致内存泄漏。
  oid scheduleTimer() { new Timer().schedule(new TimerTask() { @Override public void run() { while(true); } }, Long.MAX_VALUE && 1); } View ttButton = findViewById(R.id.tt_button); ttButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { scheduleTimer(); nextActivity(); } });
  Memory Leak 7 - TimerTask
  Sensor Manager
  最后,通过Context.getSystemService(int name)可以获取系统服务。这些服务工作在各自的进程中,帮助应用处理后台任务,处理硬件交互。如果需要使用这些服务,可以注册监听器,这会导致服务持有了Context的引用,如果在Activity销毁的时候没有注销这些监听器,会导致内存泄漏。
  void registerListener() { SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL); sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST); } View smButton = findViewById(R.id.sm_button); smButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { registerListener(); nextActivity(); } });
  Memory Leak 8 - Sensor Manager
  看过那么多会导致内存泄漏的例子,容易导致吃光的内存使垃圾回收处理更为频发,甚至最坏的情况会导致OOM。垃圾回收的操作是很昂贵的开销,会导致肉眼可见的卡顿。所以,的时候注意持有的引用链,并经常进行内存泄漏检查。
相关文章:
[ 责任编辑:杨瑗嘉 ]
HPE Octane为开发者和…
甲骨文的云战略已经完成第一阶段…
软件信息化周刊
比特软件信息化周刊提供以数据库、操作系统和管理软件为重点的全面软件信息化产业热点、应用方案推荐、实用技巧分享等。以最新的软件资讯,最新的软件技巧,最新的软件与服务业内动态来为IT用户找到软捷径。
商务办公周刊
比特商务周刊是一个及行业资讯、深度分析、企业导购等为一体的综合性周刊。其中,与中国计量科学研究院合力打造的比特实验室可以为商业用户提供最权威的采购指南。是企业用户不可缺少的智选周刊!
比特网络周刊向企业网管员以及网络技术和产品使用者提供关于网络产业动态、技术热点、组网、建网、网络管理、网络运维等最新技术和实用技巧,帮助网管答疑解惑,成为网管好帮手。
服务器周刊
比特服务器周刊作为比特网的重点频道之一,主要关注x86服务器,RISC架构服务器以及高性能计算机行业的产品及发展动态。通过最独到的编辑观点和业界动态分析,让您第一时间了解服务器行业的趋势。
比特存储周刊长期以来,为读者提供企业存储领域高质量的原创内容,及时、全面的资讯、技术、方案以及案例文章,力求成为业界领先的存储媒体。比特存储周刊始终致力于用户的企业信息化建设、存储业务、数据保护与容灾构建以及数据管理部署等方面服务。
比特安全周刊通过专业的信息安全内容建设,为企业级用户打造最具商业价值的信息沟通平台,并为安全厂商提供多层面、多维度的媒体宣传手段。与其他同类网站信息安全内容相比,比特安全周刊运作模式更加独立,对信息安全界的动态新闻更新更快。
新闻中心热点推荐
新闻中心以独特视角精选一周内最具影响力的行业重大事件或圈内精彩故事,为企业级用户打造重点突出,可读性强,商业价值高的信息共享平台;同时为互联网、IT业界及通信厂商提供一条精准快捷,渗透力强,覆盖面广的媒体传播途径。
云计算周刊
比特云计算周刊关注云计算产业热点技术应用与趋势发展,全方位报道云计算领域最新动态。为用户与企业架设起沟通交流平台。包括IaaS、PaaS、SaaS各种不同的服务类型以及相关的安全与管理内容介绍。
CIO俱乐部周刊
比特CIO俱乐部周刊以大量高端CIO沙龙或专题研讨会以及对明星CIO的深入采访为依托,汇聚中国500强CIO的集体智慧。旨为中国杰出的CIO提供一个良好的互融互通 、促进交流的平台,并持续提供丰富的资讯和服务,探讨信息化建设,推动中国信息化发展引领CIO未来职业发展。
IT专家新闻邮件长期以来,以定向、分众、整合的商业模式,为企业IT专业人士以及IT系统采购决策者提供高质量的原创内容,包括IT新闻、评论、专家答疑、技巧和白皮书。此外,IT专家网还为读者提供包括咨询、社区、论坛、线下会议、读者沙龙等多种服务。
X周刊是一份IT人的技术娱乐周刊,给用户实时传递I最新T资讯、IT段子、技术技巧、畅销书籍,同时用户还能参与我们推荐的互动游戏,给广大的IT技术人士忙碌工作之余带来轻松休闲一刻。
微信扫一扫
关注Chinabyte<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&Context作为最基本的上下文,承载着Activity,Service等最基本组件。当有对象引用到Activity,并不能被回收释放,必将造成大范围的对象无法被回收释放,进而造成内存泄漏。
下面针对一些常用场景逐一分析。
1. CallBack对象的引用
& & 先看一段代码:
protectedvoid onCreate(Bundle state){
super.onCreate(state);
TextView label =new TextView(this);
label.setText("Leaks are bad");
setContentView(label);
& & 大家看看有什么问题吗?
& & 没问题是吧,继续看:
private static Drawable sB
protected void onCreate(Bundle state){
super.onCreate(state);
TextView label =new TextView(this);
label.setText("Leaks are bad");
if(sBackground ==null){
sBackground = getDrawable(R.drawable.large_bitmap);
label.setBackgroundDrawable(sBackground);
setContentView(label);
& & 有问题吗?
& & 哈哈,先Hold住一下,先来说一下android各版本发布的历史:
, Gingerbread
, Honeycomb
Ice Cream Sandwich
& & 了解源码的历史,是很有益于我们分析android代码的。
& & 好,开始分析代码。
& & 首先,查看setBackgroundDrawable(Drawable background)方法源码里面有一行代码引起我们的注意:
public void setBackgroundDrawable(Drawable background) {
// ... ...
background.setCallback(this);
// ... ...
& & 所以sBackground对view保持了一个引用,view对activity保持了一个引用。
& & 当退出当前Activity时,当前Activity本该释放,但是因为sBackground是静态变量,它的生命周期并没有结束,而sBackground间接保持对Activity的引用,导致当前Activity对象不能被释放,进而导致内存泄露。
& & 所以结论是:有内存泄露!
& & 这是Android官方文档的例子:
& & 到此结束了吗?
& & 我发现网上太多直接抄或者间接抄这篇文章,一搜一大片,并且吸引了大量的Android初学者不断的转载学习。
& & 但是经过本人深入分析Drawable源码,事情发生了一些变化。
& & Android官方文档的这篇文章是写于2009年1月的,当时的Android Source至少是Froyo之前的。
& & Froyo的Drawable的setCallback()方法的实现是这样的:
public final void setCallback(Callback cb) {
mCallback =
& & 在GingerBread的代码还是如此的。
& & 但是当进入HoneyComb,也就是3.0之后的代码我们发现Drawable的setCallback()方法的实现变成了:
public final void setCallback(Callback cb) {
mCallback = new WeakReference&Callback&(cb);
& & 也就是说3.0之后,Drawable使用了软引用,把这个泄露的例子问题修复了。(至于软引用怎么解决了以后有机会再分析吧)
& & 所以最终结论是,在android3.0之前是有内存泄露,在3.0之后无内存泄露!
& & 如果认真比较代码的话,Android3.0前后的代码改进了大量类似代码,前面的Cursor篇里的例子也是在3.0之后修复了。
& & 从这个例子中,我们很好的发现了内存是怎么通过回调泄露的,同时通过官方代码的update也了解到了怎么修复类似的内存泄露。
2. System Service对象
& & 通过各种系统服务,我们能够做一些系统设计好的底层功能:
//ContextImpl.java
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
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);
// ... ...
  这些其实就是定义在Context里的,按理说这些都是系统的服务,应该都没问题,但是代码到了各家厂商一改,事情发生了一些变化。
& & & 一些厂商定义的服务,或者厂商自己修改了一些新的代码导致系统服务引用了Context对象不能及时释放,我曾经碰到过Wifi,Storage服务都有内存泄露。
& & &我们改不了这些系统级应用,我们只能修改自己的应用。
& & &解决方案就是:使用ApplicationContext代替Context。
& & &举个例子吧:
// For example
mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
mStorageManager = (StorageManager) getApplicationContext().getSystemService(Context.STORAGE_SERVICE);
3. Handler对象
& & 先看一段代码:
public class MainActivity extends QActivity {
// lint tip: This Handler class should be static or leaks might occur
class MyHandler extends Handler {
& & Handler泄露的关键点有两个:
& & 1). 内部类
& & 2). 生命周期和Activity不一定一致
& & 第一点,Handler使用的比较多,经常需要在Activity中创建内部类,所以这种场景还是很多的。
& & 内部类持有外部类Activity的引用,当Handler对象有Message在排队,则无法释放,进而导致Activity对象不能释放。
& & 如果是声明为static,则该内部类不持有外部Acitivity的引用,则不会阻塞Activity对象的释放。
& & 如果声明为static后,可在其内部声明一个弱引用(WeakReference)引用外部类。
public class MainActivity extends Activity {
private CustomHandler mH
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new CustomHandler(this);
static class CustomHandlerextends Handler {
// 内部声明一个弱引用,引用外部类
private WeakReference&MainActivity & activityWeakR
public MyHandler(MyActivity activity) {
activityWeakReference= new WeakReference&MainActivity &(activity);
// ... ...
& & 第二点,其实不单指内部类,而是所有Handler对象,如何解决上面说的Handler对象有Message在排队,而不阻塞Activity对象释放?
& & 解决方案也很简单,在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。
& &&通过查看Handler的API,它有几个方法:removeCallbacks(Runnable&r)和removeMessages(int what)等。
// 一切都是为了不要让mHandler拖泥带水
public void onDestroy() {
mHandler.removeMessages(MESSAGE_1);
mHandler.removeMessages(MESSAGE_2);
mHandler.removeMessages(MESSAGE_3);
mHandler.removeMessages(MESSAGE_4);
// ... ...
mHandler.removeCallbacks(mRunnable);
// ... ...
& & 上面的代码太长?好吧,出大招:
public void onDestroy() {
If null, all callbacks and messages will be removed.
mHandler.removeCallbacksAndMessages(null);
& & 有人会问,当Activity退出的时候,我还有好多事情要做,怎么办?我想一定有办法的,比如用Service等等.
4. Thread对象
& & 同Handler对象可能造成内存泄露的原理一样,Thread的生命周期不一定是和Activity生命周期一致。
& & 而且因为Thread主要面向多任务,往往会造成大量的Thread实例。
& & 据此,Thread对象有2个需要注意的泄漏点:
& & 1). 创建过多的Thread对象
& & 2). Thread对象在Activity退出后依然在后台执行
& & 解决方案是:
& & 1). 使用ThreadPoolExecutor,在同时做很多异步事件的时候是很常用的,这个不细说。
& & 2). 当Activity退出的时候,退出Thread。
& & 第一点,例子太多,建议大家参考一下afinal中AsyncTask的实现学习。
& & 第二点,如何正常退出Thread,我在之前的博文中也提到过。示例代码如下:
// ref /javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html
private volatile T
public void stop() {
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
thisThread.sleep(interval);
} catch (InterruptedException e){
repaint();
& & 有人会问,当Activity退出的时候,我还有好多事情要做,怎么办?请看上面Handler的分析最后一行。
& & (未完待续)
阅读(...) 评论()Android&Handler&解决警告和内存泄漏
在项目中使用Handler时:&&&
private&Handler&mHandler&=&new&Handler()&{
&&&&&&&&@Override
&&&&&&&&public&void&handleMessage(Message&msg)&{
&&&&&&&&};
会出现警告提示<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blog.csdn.net/wwzqj/article/details/" ALT=""
TITLE="Android&Handler&解决警告和内存泄漏" />,也会在Problems中进行统计和显示,如下:
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blog.csdn.net/wwzqj/article/details/" ALT=""
TITLE="Android&Handler&解决警告和内存泄漏" />
把鼠标放在报错<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blog.csdn.net/wwzqj/article/details/" ALT="" STYLE="color:rgb(17,17,17); line-height:25px"
TITLE="Android&Handler&解决警告和内存泄漏" />处,就会提示This Handler class
should be static or leaks might occur,如下:
&&&&@SuppressLint("HandlerLeak")
&&&&private&Handler&mHandler&=&new&Handler()&{
&&&&&&&&@Override
&&&&&&&&public&void&handleMessage(Message&msg)&{
&&&&&&&&};
解决方法:
&&&&private&Handler&mHandler&=&new&Handler(new&Handler.Callback()&{
&&&&&&&&@Override
&&&&&&&&public&boolean&handleMessage(Message&msg)&{
&&&&&&&&&&&&return&
用第一种有时会出现警告,提示用静态的类和造成内存泄漏的情况;
用第二种可以避免第一种出现的问题和内存泄漏,相当于runnable。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。& & & Android开发经常会用到handler,但是我们发现每次使用Handler都会出现:This Handler class should be static or leaks might occur(null)这样的提示。Android lint就是为了提示我们,这样使用Handler会容易造成内存泄漏。但是你会发现其实改成static并没有什么用。因为这并没有解决这个问题的根本。
  首先,我们得确认,为什么会有内存泄漏?因为Handler是基于消息的。每次new 出Handler,都会创建一个消息队列用于处理你使用handler发送的消息,形如:handler.send***Message。由于消息的发送总是会有先来后到的区别(如果只是这样都还好,毕竟再慢也不会太久,总归可以跑完,可能会延迟个几秒),但是如果你使用的是sendMessageDelayed(Message msg, long delayMillis)或postDelayed(Runnable r, long delayMillis)等发送延迟消息的时候,那基本内存泄漏发生的概率已经在90%以上了。
& & &我举个通常的例子,就是我们在Activity中使用handler来更新UI控件,这是比较常见的。
1 public class DemoActivity extends Activity {
private Handler mH
protected void onCreate(Bundle savedInstanceState) {
mHandler = new Handler();
8      mHandler.postDelayed(new Runnable() {
9        Log.i("wytings","-----------postDelayed-------");
view.setVisibility(View.GONE);
}, 50000);
& & & 如果我们疯狂的对这个Activity进行横屏和竖屏切换的话,那么Activity就会不断的被销毁和重建。理论上被关闭的Activity应该会再特定时候被回收,也就是我们的内存会在一定的范围内上下起伏,但是实际上,会发现消耗的内存会随着切换横屏的次数一直慢慢增加。这其实已经说明我们的内存泄漏了,如果你会查看内存,你会发现里面有成堆的DemoActivity实例没办法回收。
  这是因为view中使用的Context就是当前的Activity,而这个runnable一旦被post,就会一直存在于队列里面,直到时间到了,被执行。意思是这个时间段内Activity即使已经被destroy了但是这个对象还是没办法回收,你会发现50秒好,会有一堆"-----------postDelayed-------"的log打印出来,虽然你已经被这个应用关闭了并且你以为即使打印也应该只打印一次&&
  那怎么样才可以避免这中问题呢,如果你网上一搜你会看到很多关于弱引用的文章。这确实是一个解决的办法。其原理就是让所有在handler里面使用的对象都变成弱引用,目的就是为了可以在Android回收内存的时候,可以直接回收掉。我真觉得如果只是写这种办法的人,绝对是属于拷贝党,因为这完全是就事论事。你想想就明白,我们写这个Handler是因为我们要使用它。怎么可以通过这种弱引用的办法去处理这类问题呢?让JVM想回收就回收?!如果这样,那我们还需要在使用Bitmap的时候,recycle()干嘛,还不如直接弄成软引用得了。
这里需要再插播一下关于Java里面引用的知识:
强引用(Strong Reference)
默认引用。如果一个对象具有强引用,垃圾回收器绝不会回收它。在内存空 间不足时,Java虚拟机宁愿抛出OutOfMemory的错误,使程序异常终止,也不会强引用的对象来解决内存不足问题。
软引用(SoftReference)
如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。
弱引用(WeakReference)
在垃圾回收器一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
虚引用(PhantomReference)
如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
& & & 如果你运气好,你会碰到一些除了写弱引用这个方法后,还有一个就是handler.removeCallbacksAndMessages(null);,就是移除所有的消息和回调,简单一句话就是清空了消息队列。注意,不要以为你post的是个Runnable或者只是sendEmptyMessage。你可以看一下源码,在handler里面都是会把这些转成正统的Message,放入消息队列里面,所以清空队列就意味着这个Handler直接被打成原型了,当然也就可以回收了。
  所以,我觉得最好的办法就是你在使用Handler的时候,在外面的Activity或者Fragment中的关闭方法中,如onDestroy中调用一下handler.removeCallbacksAndMessages(null);就可以了,不应该改成软引用。
转自:/wytings/p/5225278.html
阅读(...) 评论()}

我要回帖

更多关于 handler内存泄漏 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信