关于android中使用new Message的内存泄露问题

我们在android上发消息的时候,使用

Message msg=new Message()

后,发现整夜播放系统提示OOM,程序重启。将new Message()换成

Message.obtain();

后,内存泄露消失。

 

查了下android的source code,除了测试代码外,基本上都是使用后者方法,没有用前面的方法,确定是new Message泄露了。

 

继续追了下源码,终于看到问题了。就在Message.java中,可以看到问题的症结:

 

Message是通过一个message pool(消息池)来存储消息资源的,默认这个池子的大小是10个消息资源。代码片段:

  private static Object mPoolSync = new Object(); private static Message mPool; private static int mPoolSize = 0; private static final int MAX_POOL_SIZE = 10; /** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain() { synchronized (mPoolSync) { if (mPool != null) { Message m = mPool; mPool = m.next; m.next = null; return m; } } return new Message(); }

这里可以看到,使用obtain()方法,会从池子里获取一个消息。 当没有可用的空余资源时,new一个。

 

再看一下,当looper处理完一个消息时,调用的recyle:

/** * Return a Message instance to the global pool. You MUST NOT touch * the Message after calling this function -- it has effectively been * freed. */ public void recycle() { synchronized (mPoolSync) { if (mPoolSize < MAX_POOL_SIZE) { clearForRecycle(); next = mPool; mPool = this; } } }

这里的意思就是,当looper用完一个消息后,调用recycle,当当前的pool size没达到MAX_POOL_SIZE的时候,将此消息归还给消息池子。

 

这里看起来也没啥问题,但通篇搜索了google的源代码,也没看到在哪里修改了mPoolSize。如果不改,这个值一直为0,那么不管是通过new Message()还是通过Message.obtain()方法获取的Message,都归还给Message Pool了。通过new出来的message就无法被GC掉,这样就是内存泄露!!

 

一个可行的修改方法(没测试)

  public static Message obtain() { synchronized (mPoolSync) { if (mPool != null) { Message m = mPool; mPool = m.next; m.next = null; mPoolSize --; return m; } } return new Message(); }

public void recycle() { synchronized (mPoolSync) { if (mPoolSize < MAX_POOL_SIZE) { mPoolSize++; clearForRecycle(); next = mPool; mPool = this; } } }

 

按理说这是一个很小的问题,不知道google为何没修,而是所有的使用上都是通过obtain的方式来实现。是否有何讲究没?

 

 

 

 

你可能感兴趣的:(android,object,function,Google,测试,null)