面试串讲012-主线程每5秒钟发一个需要执行10秒的消息到子线程,会发生什么?

75 阅读2分钟

问题:

主线程每5秒钟发一个执行10秒的消息到子线程,会发生什么?

回答:

主线程每5秒钟发一个执行10秒的消息到子线程,假设在整个过程中,不论是主线程的5秒定时发送,还是子线程10s执行的逻辑都能正常按预期得到CPU按时执行,那么对于子线程而言,每10秒可以在其消息队列中形成一个消息堆积,当时间足够长的时候,因为内存不足以构造新的Message对象,进而导致OOM异常。

解析

编写测试代码,每5秒向HandlerThread发送一条消息,该消息需执行10秒,为减少测试时间,发往HandlerThread的消息obj指定为大内存对象,代码如下:

 public class MemoryTest extends AppCompatActivity {
     private static final String TAG = "MemoryTest";
     private static final int MSG_WHAT = 100;
     private static final int MAIN_DELAY_MILLIS = 5000;
     private static final int BG_DELAY_MILLIS = 10000;
     private HandlerThread mHandlerThread;
     private Handler mBgHandler;
     private Handler mMainHandler;
 ​
 ​
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_memory_test);
         mHandlerThread = new HandlerThread("BG_HANDLER");
         mHandlerThread.start();
         mBgHandler = new Handler(mHandlerThread.getLooper()) {
             @Override
             public void handleMessage(@NonNull Message msg) {
                 if (msg.what == MSG_WHAT) {
                     // 处理子线程消息,执行10s
                     SystemClock.sleep(BG_DELAY_MILLIS);
                     return;
                 }
                 super.handleMessage(msg);
             }
         };
         mMainHandler = new Handler(Looper.getMainLooper()) {
             @Override
             public void handleMessage(@NonNull Message msg) {
                 if (msg.what == MSG_WHAT) {
                     // 打印HandlerThread消息队列的排队情况
                     mHandlerThread.getLooper().dump(new Printer() {
                         @Override
                         public void println(String x) {
                             Log.d(TAG, x);
                         }
                     }, TAG);
                     Message message = new Message();
                     message.what = MSG_WHAT;
                     // message.obj是一个1M内存占用的大对象
                     message.obj = new byte[1024 * 1024];
                     // 向子线程发送消息
                     mBgHandler.sendMessage(message);
                     // 触发主线程消息消息循环
                     mMainHandler.sendEmptyMessageDelayed(MSG_WHAT, MAIN_DELAY_MILLIS);
                     return;
                 }
                 super.handleMessage(msg);
             }
         };
         mMainHandler.sendEmptyMessage(MSG_WHAT);
 ​
     }
 }

在Genymotion模拟器上执行上述测试代码,当队列中堆积消息数量达到92个时,再次创建发送给子线程的Message失败,爆出OOM异常,日志打印如图所示:

mianshi012-1

综上,当我们使用主线程定时5秒向子线程发送一个执行10秒的消息时,等待时间足够长且不清理子线程消息队列的情况下,会发生OOM异常。