自分のアプリの幾つかではAdmobで広告を表示しています。
UsbWebCameraもその1つです。現在Android5.0対応版を作っているんですが、アプリ終了時にAdmob関係でリークしてしまうのです。
ログはこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Activity com.serenegiant.usbwebcamera.MainActivity has leaked ServiceConnection com.google.android.gms.common.b@42a8cac8 that was originally bound here android.app.ServiceConnectionLeaked: Activity com.serenegiant.usbwebcamera.MainActivity has leaked ServiceConnection com.google.android.gms.common.b@42a8cac8 that was originally bound here at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:970) at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:864) at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1569) at android.app.ContextImpl.bindService(ContextImpl.java:1552) at android.content.ContextWrapper.bindService(ContextWrapper.java:517) at com.google.android.gms.ads.identifier.a.b(SourceFile:330) at com.google.android.gms.ads.identifier.a.a(SourceFile:187) at com.google.android.gms.ads.identifier.a.a(SourceFile:173) at com.google.android.a.u.a(SourceFile:79) at com.google.android.a.u.doInBackground(SourceFile:75) at android.os.AsyncTask$2.call(AsyncTask.java:288) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:841) |
でこの結果どんなことになるかというと、メモリもそうなんですがスレッドがえらいことになるんです。
Admob広告を使わない時
まずは参考のために広告無しの場合のスレッドを載せます。
1 21101 Native 61 13 main
*2 21105 VmWait 4 0 GC
*3 21106 VmWait 0 0 Signal Catcher
*4 21107 Runnable 0 5 JDWP
*5 21108 VmWait 3 2 Compiler
*6 21109 Wait 0 0 ReferenceQueueDaemon
*7 21110 Wait 2 0 FinalizerDaemon
*8 21111 Wait 0 0 FinalizerWatchdogDaemon
9 21112 Native 0 0 Binder_1
10 21113 Native 0 0 Binder_2
11 21363 Native 0 0 SoundPoolThread シャッター音用
12 21116 Native 0 0 Thread-403 これは自前のカメラ用のスレッド
13 21362 Native 0 0 SoundPool シャッター音用
14 21124 Native 0 0 background thread
16 21162 Wait 1 0 pool-2-thread-1 これはThreadExecutor(自前)
17 21172 Native 0 0 Binder_3
グレーはシステムのスレッドとアプリメインスレッド、青は自前で生成、または自前で生成したオブジェクトに付随するスレッドです。
実際にカメラに接続してプレビュー表示すればもう少しスレッドは増えますが、広告無しであれば画面を回転させてActivityが再生成されてもスレッドの数は変わりません。
Admob広告を使った時
Admob広告有りの起動直後のスレッド
一方Admob広告有りで動かすと、起動直後はこんな感じです。
1 21659 Native 2227 480 main
*2 21663 VmWait 0 3 GC
*3 21664 VmWait 0 0 Signal Catcher
*4 21665 Runnable 2 4 JDWP
*5 21666 VmWait 10 3 Compiler
*6 21667 Wait 0 0 ReferenceQueueDaemon
*7 21668 Wait 2 1 FinalizerDaemon
*8 21669 Wait 0 0 FinalizerWatchdogDaemon
9 21670 Native 0 0 Binder_1
10 21671 Native 0 0 Binder_2
11 21678 Native 0 0 Thread-406 これは自前のカメラ用のスレッド
12 21679 Native 0 0 SoundPool シャッター音用
13 21680 Native 0 0 SoundPoolThread シャッター音用
14 21687 Native 0 0 background thread
15 21850 Wait 0 0 AdWorker #6
16 21697 Wait 0 1 AdWorker #1
17 21700 Native 0 0 SettinsObserver
18 21706 Native 19 11 Thread-415
19 21701 Native 0 0 Thread-416
20 21712 Wait 7 4 AdWorker #2
21 21714 Wait 0 0 AsyncTask #1
22 21851 TimedWait 0 0 Thread-431
23 21728 Wait 0 0 AdWorker #3
*24 21743 Wait 0 0 CleanupReference
25 21745 Wait 0 0 AdWorker #4
26 21746 Native 1076 75 Thread-425
27 21754 Native 827 84 Thread-426
28 21758 Wait 6 3 AdWorker #5
29 21870 Wait 0 0 AdWorker #8
30 21761 Native 11 4 Thread-429
31 21862 Wait 0 0 AdWorker #7
32 21871 Native 172 17 Thread-434
33 21872 Wait 0 0 AdWorker #9
*34 21873 TimedWait 0 0 OkHttp ConnectionPool
赤いところが広告を表示させたら増えた部分。広告そのものと広告表示用のWebViewのものが混在しています。ちょっと多いなぁとは思いますがまぁこれはいんですよ。次ですよ次(・o・)
Admob広告有りで20回ほど端末を回転させた時のスレッド
端末を20回ほど回転させてActivityの再生成を繰り返した後のスレッドです。
1 21659 Runnable 6530 1416 main
*2 21663 VmWait 0 6 GC
*3 21664 VmWait 0 0 Signal Catcher
*4 21665 Runnable 7 18 JDWP
*5 21666 VmWait 18 12 Compiler
*6 21667 Wait 0 1 ReferenceQueueDaemon
*7 21668 Wait 5 3 FinalizerDaemon
*8 21669 TimedWait 0 0 FinalizerWatchdogDaemon
9 21670 Native 1 0 Binder_1
10 21671 Native 2 0 Binder_2
11 22571 Native 0 0 Thread-487
12 23258 Native 0 0 SoundPoolThread
13 22186 Native 0 0 Thread-450
14 22741 Native 0 0 Thread-509
15 21850 Wait 0 0 AdWorker #6
16 21697 Wait 1 1 AdWorker #1
17 21700 Native 0 0 SettinsObserver
18 21706 Native 62 39 Thread-415
19 21701 Native 0 0 Thread-416
20 21712 Wait 11 4 AdWorker #2
21 21714 Wait 0 0 AsyncTask #1
22 21993 Wait 4 2 AdWorker #10
23 21728 Wait 0 0 AdWorker #3
*24 21743 Wait 0 0 CleanupReference
25 21745 Wait 0 0 AdWorker #4
26 21746 Native 3106 231 Thread-425
27 22114 Native 0 0 Thread-443
28 21758 Wait 12 3 AdWorker #5
29 21870 Wait 3 0 AdWorker #8
30 21761 Native 11 4 Thread-429
31 21862 Wait 3 2 AdWorker #7
32 22129 Native 0 0 Thread-444
33 21872 Wait 4 1 AdWorker #9
34 22113 Wait 6 3 pool-5-thread-1
*35 22012 TimedWait 0 0 OkHttp ConnectionPool
37 23286 TimedWait 0 0 Thread-575
38 22586 Native 0 0 background thread
39 22239 Native 0 0 Thread-455
40 22264 Native 0 0 Thread-460
41 22342 Native 0 0 Thread-465
42 22367 Native 0 0 Thread-470
43 22410 Native 0 0 Thread-475
44 22464 Native 0 0 Thread-480
45 22503 Native 0 0 Thread-486
46 22496 Native 1 0 Binder_3
47 22604 Native 0 0 Thread-495
48 22637 Native 21 21 Thread-497
49 22710 Native 0 0 Thread-504
50 23111 Native 0 0 Thread-554
51 22799 Native 0 0 Thread-514
52 22853 Native 0 0 Thread-519
53 22886 Native 0 0 Thread-524
54 22926 Native 0 0 Thread-529
55 22954 Native 0 0 Thread-534
56 22994 Native 0 0 Thread-539
57 23033 Native 0 0 Thread-544
58 23064 Native 0 0 Thread-549
59 23257 Native 0 0 SoundPool
60 23150 Native 0 0 Thread-559
61 23177 Native 0 0 Thread-564
62 23232 Native 0 0 Thread-569
63 23256 Native 0 0 Thread-574
64 23298 Native 42 5 Thread-576
最初にどっと増えて後はActivityが1回生成するたびに1つずつ際限なく増えていく感じです。しかもアプリを強制終了するまで減ることはありません。
Admobのサイトに書いてあるとおりに、Activityのライフサイクルに合わせて生成・pause・destroy等を呼んでます。そもそもフロントエンドの部分のソースは今公開しているのと殆ど一緒・Activity(広告)部分はずっと一緒なのに〜(´・ω・`)
最初はAndroid5.0(もしくは新しいWebView)関係の問題かと思ったのですがNexus5(Android4.4.4)でも起こります。
GooglePlay開発者サービスのライブラリプロジェクトを更新してなくて(^_^;)少し古いまま使っていたのが原因かと思い、最新のにすげ替えてもやっぱり一緒。
ちなみに現在公開しているバージョンをインストールして動かしてみると・・・たっ大変だ〜やっぱり終了時にリークしてる(-_-;)
昔からあるWebViewのリーク絡みなんかな?自分はWebViewを殆ど使わないから大丈夫かなぁと思ってたんだけどこんなところに落とし穴が(´・ω・`)
どうすんのこれ〜。
AdmobのサイトでもStackOverflowでも調べて見てみましたが、3日前(12/8)の時点では解決策は無いとのこと。
表示にWebViewを使っているようなので、こんなコードを入れて終了時にAdView内のWebViewを探し当ててWebViewのクリーンアップをしてみた。
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 |
private WebView findWebView(ViewGroup holder) { WebView result = null; final int n = holder.getChildCount(); View child; for (int i = 0; i < n; i++) { child = holder.getChildAt(i); Log.i(TAG, "child=" + child); if (child instanceof WebView) { Log.i(TAG, "found"); result = (WebView)child; break; } else if (child instanceof ViewGroup) { result = findWebView((ViewGroup)child); } } return result; } /** * 広告の破棄・開放処理 */ private final void freeAdView() { if (adView != null) { // WebViewを探す WebView view = findWebView(mAds_parent); if (view != null) { view.stopLoading(); view.setWebChromeClient(null); view.setWebViewClient(null); view.destroy(); view = null; } mAds_parent.removeView(adView); adView.destroy(); adView = null; adHeight = 0; System.gc(); } } |
WebViewは見つかって破棄できるんだけどリークには全然効果がなかった(T_T)
っとっとりあえず見なかったことにしようっ、でいいんかいな?
m(_ _)m