私のAndroid4.0.4アプリケーションは、ユーザーがアセットディレクトリにローカルに保存されている複数のページを表示できるWebViewで構成されています。ページを循環すると、最終的に次のエラーがトリガーされ、アプリケーションがクラッシュします。
- JNIエラー(アプリのバグ):ローカル参照テーブルのオーバーフロー(最大= 512)
- JNIローカル参照テーブルへの追加に失敗しました(512エントリあり)
- VMの中止
- 0xdeadd00dd(コード= 1)での致命的な信号11(SIGSEGV)
この問題は、ここで報告されている問題に関連しているようです。
詳細を調べるために、次のリンクにあるメモリアナライザツールプラグインの手順を使用しました。
http://therockncoder.blogspot.ca/2012/09/fixing-android-memory-leak.html
結果を以下に示します(まだ画面キャプチャを投稿できないため、テキストで投稿する必要があります)。
MATの抜粋
Class Name | Shallow Heap | Retained Heap | Percentage
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| | |
java.lang.Thread @ 0x40daa320 Thread-39775 Thread | 80 | 15,310,552 | 76.74%
|- byte[32768] @ 0x40d5a8d0 <!DOCTYPE html>.<html xml:lang="">.<head>. <title>Android Test-HTML5-480PX-Page 0</title>. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />. <meta name="viewport" content="width=360, height=480">. <!--. <meta name="viewport" co...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40e25bb8 on-play-state: running;. -webkit-animation-timing-function: step-start;. }. @-webkit-keyframes ag16780-anim45051. {. 0.000% { background-position:0px 0px,77px 0px,77px 0px,77px 0px,77px 0px,77px 0px; }. 20.000% { background-position...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40e60520 //<![CDATA[.var pageParams = new Object();.pageParams['readMode'] = 1;...function applyReadMode().{. var audioNodes = document.getElementsByClassName('BGAudio');. for (var i=0; i<audioNodes.length; i++). {. .if (pageParams['readMode'] == 0). ...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40e86f48 .PNG........IHDR....... ......U......gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....bKGD..............pHYs...#...#.x.?v...ZIDATH..U]l\W..f.9.......8..G.....Z$ZUi..*EQQ...RE.Hi.D".0BTj..J.x..O.J..C.)..IU.R......HB.8..&..\.x..w..{fx...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40f09f00 html.{. padding : 0px 0px 0px 0px;. margin : 0px 0px 0px 0px;. height : 100%;. width : 100%;. background : #ffffff;.}.body.{. padding : 0px 0px 0px 0px;. margin : 0px 0px...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x40f11f18 .=Xt.....H...hE:t.;.......=.s....f.(.....v.5'<.8}=.=kXF..&&...K...j.........<...A..........}.......c.c..7.e{b.....O.p..h....e.1....8.zd{..........}3.Z.W..v.|}y.u...3M.....h2IDAT...........Z.;u..M.....'!.(.S.....|j.]..h.l7.... .....I...u.&J5.";9.d04.S.........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41009af0 //<![CDATA[.var pageParams = new Object();.pageParams['readMode'] = 1;...function applyReadMode().{. var audioNodes = document.getElementsByClassName('BGAudio');. for (var i=0; i<audioNodes.length; i++). {. .if (pageParams['readMode'] == 0). ...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41011b08 html.{. padding : 0px 0px 0px 0px;. margin : 0px 0px 0px 0px;. height : 100%;. width : 100%;. background : #ffffff;.}.body.{. padding : 0px 0px 0px 0px;. margin : 0px 0px...| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41019b20 ...t.%#2#b......0..0.6.....A.M....%.F,.*...(.>.q$_.0... a..sF...."Ypn"....#.q...@...........C...3....-.L.b.A).F....4.....Q.1.Wd..3.|.Y%........:.w.F~ ]..0i>a......4n.E7.O..+.7S...D...|.IDAT..'...<.....E.n...!.1.....Tx211..E....4 .*f....>..)..)...gS.j.. WX....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41021b38 .PNG........IHDR...|.................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....PLTE.................................................................................................................................................| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41029b50 .PNG........IHDR.......Q.......0.....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....bKGD..............pHYs...#...#.x.?v..:.IDATx...gx...........-.....4...p...S....%$!$.$$....z....8T.:.L...c..wI......23..3....U...?.5..j.......J@.P....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41031b68 .PNG........IHDR...V.........0..X....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....bKGD..............pHYs...#...#.x.?v....IDATh..Zyp.U....f.;3....j0..p...E]...M...*%..,.J..Pb..,....Z.AE.E.....n.."A.........@..d...>...........W......| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410889d0 .PNG........IHDR.............a.~e....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....PLTE...Q_HRgL......=I93?/f~Zg~[DV=@P8)0$'2&(3&/<('1$......""!:;:"#"......)3&...............&&&'''.......... ...........$.677888.$....................| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410909e8 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE........~..............v...........~.........{yn........................................................F.. ..4..............!...........+..l....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x41098a00 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE...uuj....................i.......................................................................S..'..$..............*..............[..........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410a0a18 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...tPLTE...llh...........................|.u.....................................................]..*..+..............-..............T..............M....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410a8a30 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE...ooi.......................}....................................................................[..)..%..............+..............Y..........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410b0a48 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...zPLTE...wvk.......................{....................................................................\..(..$..............,..............\..........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410b8a60 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...zPLTE...rqg.....d...................................z........................................................R..%.. ..............(..............]....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410c0a78 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE...rrh........r............................................................................................Q..%.. ..............(................| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410c8a90 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...wPLTE........}..............O...........|.........xwl........................................................G..!.....8.............."...........'....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410d0aa8 .PNG........IHDR.....................gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...zPLTE........~..............m...........~.........{yn........................................................F.. ..4..............!...........+..l....| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410d8ac0 .PNG........IHDR.............e.. ....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...yPLTE...mmmhfZ........h.................)........c..kppp..h..u.......................................................................x..o..a..........| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410e0ad8 .PNG........IHDR.............e.. ....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<....PLTE...hhh.......................-...........e..~........|.............................................................................s.............| 32,784 | 32,784 | 0.16%
|- byte[32768] @ 0x410e8af0 .PNG........IHDR.............e.. ....gAMA......a.....sRGB........ cHRM..z&..............u0...`..:....p..Q<...|PLTE.........,,+........c..~...........]..............y....................n.........................................................................| 32,784 | 32,784 | 0.16%
'- Total: 25 of 471 entries; 446 more | | |
android.widget.HorizontalScrollView @ 0x40e1d8b8 | 576 | 978,456 | 4.90%
class android.content.res.Resources @ 0x40ab1570 System Class | 48 | 266,432 | 1.34%
...
ログの抜粋
...
10-08 22:10:28.970: D/MediaPlayer(9823): pause() out
10-08 22:10:29.090: E/dalvikvm(9823): JNI ERROR (app bug): local reference table overflow (max=512)
10-08 22:10:29.090: W/dalvikvm(9823): JNI local reference table (0x2498270) dump:
10-08 22:10:29.090: W/dalvikvm(9823): Last 10 entries (of 512):
10-08 22:10:29.090: W/dalvikvm(9823): 511: 0x40d696d0 android.content.res.AssetManager
10-08 22:10:29.090: W/dalvikvm(9823): 510: 0x4201eab0 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 509: 0x42016a98 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 508: 0x4200ea80 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 507: 0x42006a68 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 506: 0x41ffea50 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 505: 0x41ff6a38 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 504: 0x41feea20 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 503: 0x41fe6a08 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): 502: 0x41fde9f0 byte[] (32768 elements)
10-08 22:10:29.090: W/dalvikvm(9823): Summary:
10-08 22:10:29.090: W/dalvikvm(9823): 1 of java.lang.Class
10-08 22:10:29.090: W/dalvikvm(9823): 510 of byte[] (32768 elements) (510 unique instances)
10-08 22:10:29.090: W/dalvikvm(9823): 1 of android.content.res.AssetManager
10-08 22:10:29.090: E/dalvikvm(9823): Failed adding to JNI local ref table (has 512 entries)
10-08 22:10:29.090: I/dalvikvm(9823): "Thread-39898" prio=5 tid=12 RUNNABLE
10-08 22:10:29.090: I/dalvikvm(9823): | group="main" sCount=0 dsCount=0 obj=0x40d6b9d8 self=0x222a030
10-08 22:10:29.090: I/dalvikvm(9823): | sysTid=9871 nice=0 sched=0/0 cgrp=default handle=29456640
10-08 22:10:29.090: I/dalvikvm(9823): | schedstat=( 520906000 142824000 757 ) utm=22 stm=30 core=2
10-08 22:10:29.090: I/dalvikvm(9823): at android.content.res.AssetManager.readAsset(Native Method)
10-08 22:10:29.090: I/dalvikvm(9823): at android.content.res.AssetManager.access$700(AssetManager.java:35)
10-08 22:10:29.090: I/dalvikvm(9823): at android.content.res.AssetManager$AssetInputStream.read(AssetManager.java:648)
10-08 22:10:29.090: I/dalvikvm(9823): at dalvik.system.NativeStart.run(Native Method)
10-08 22:10:29.090: E/dalvikvm(9823): VM aborting
10-08 22:10:29.090: A/libc(9823): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1)
10-08 22:10:29.140: I/MediaPlayer(9823): setLPAflag() in
...
MATエントリを見ると、メインスレッドがすべてのHTMLページ、CSSおよびJavascriptファイル、画像、オーディオファイルへの参照を保持しており、それらを解放していないように見えます。最終的に、新しいURLが呼び出されると、AssetManagerはJNIローカル参照テーブルの境界(512エントリ)を超えてエントリを書き込もうとし、使用可能なスペースを使い果たし、メモリリークを引き起こします。
私は運が悪かったので、参照を保持しないようにするためにあらゆる種類のことを試みました。これも:
ページをキャッシュしないようにWebViewを初期化する:
mWebView.getSettings().setAppCacheEnabled(false); mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); mWebView.setDrawingCacheEnabled(false);
次のページをロードする前に、既存のすべてのWebViewデータを削除しようとしています。
mWebView.stopLoading(); mWebView.clearCache(true); mWebView.destroyDrawingCache(); mWebView.clearHistory(); mWebView.freeMemory(); mWebView.getInstance().deleteAllData();
res / layout XMLを介してではなく動的にWebViewを作成し、それにActivityコンテキストではなくapplicationContextを割り当てます。
mWebView = new WebView(getApplicationContext());
ページを変更する前に現在のWebViewを破棄し、次のページ用に新しいWebViewを動的に作成しますが、これはアプリケーションの速度を低下させる以外の効果はありません。JNIローカルテーブルは引き続き古い参照を保持します。
mWebViewContainer.removeViewAt(0); mWebView.destroyDrawingCache(); mWebView.destroy(); mWebView = null; System.gc();
理想的なのは、次のページをロードする前にJNIテーブルの古いエントリを削除することですが、それを行う方法は見つかりませんでした。URLが呼び出されると、アセットディレクトリの参照は私が行ったことに関係なく保持されます。試しました。何かを見逃したか、Androidの今後のリリースで修正が保留されている可能性がありますか?これに失敗すると、ページごとに新しいWebViewを破棄して作成するとパフォーマンスに悪影響を及ぼし、デザインが複雑になりますが、ページを独自のスレッド内に作成し、メインスレッドではなく独自のアセット参照を保持できる場合は、うまくいく可能性があります(これらのスレッドは、ページの変更中に停止できる場合に限ります)。
アップデート
別のスレッドでWebViewを作成しようとすると、「すべてのWebViewメソッドをUIスレッドで呼び出す必要があります。WebViewの将来のバージョンは他のスレッドでの使用をサポートしない可能性があります。 」というエラーが発生しました。「UIスレッド」はメインスレッドを指していると思います。この投稿はそれをサポートしているようです: