5

我的 Android 4.0.4 应用程序由一个 WebView 组成,用户可以通过它查看本地存储在资产目录中的多个页面。循环浏览页面时,最终会触发以下错误并且应用程序崩溃:

  • JNI ERROR (app bug): local reference table overflow (max=512)
  • 添加到 JNI 本地引用表失败(有 512 个条目)
  • 虚拟机中止
  • 致命信号 11 (SIGSEGV) 在 0xdeadd00dd (code=1)

该问题似乎与此处报告的问题有关:

我已使用以下链接中提供的 Memory Analyzer Tool 插件说明来检查详细信息:

http://therockncoder.blogspot.ca/2012/09/fixing-android-memory-leak.html

结果如下所示(还不能发布屏幕截图,所以必须做文字):

垫节选

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 本地 ref 表边界(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();
    
  • 动态创建 WebView 而不是通过 res/layout XML,并将其分配给应用程序上下文而不是 Activity 上下文:

    mWebView = new WebView(getApplicationContext());
    
  • 在更改页面之前销毁当前的 WebView 并为下一页动态创建一个新的 WebView,但这除了减慢应用程序的速度之外没有任何影响;JNI 本地表仍然保留旧的引用:

    mWebViewContainer.removeViewAt(0);
    mWebView.destroyDrawingCache();
    mWebView.destroy();
    mWebView = null;
    System.gc();
    

理想的做法是在加载下一页之前删除 JNI 表中的旧条目,但我发现没有办法这样做——一旦调用了 URL,尽管我已经保存了资产目录引用试过了。也许我错过了一些东西,或者在更高版本的 Android 中正在等待修复?如果做不到这一点,即使为每个页面销毁和创建新的 WebView 会对性能产生负面影响并且会使设计复杂化,但如果页面可以在自己的线程中创建并持有自己的资产引用而不是主线程,那么也许这会起作用(前提是这些线程可以在页面更改期间停止)。

更新

我尝试在单独的线程中创建我的 WebView 并得到错误“必须在 UI 线程上调用所有 WebView 方法。WebView 的未来版本可能不支持在其他线程上使用。 ”。我假设“UI 线程”是指主线程。这个帖子似乎支持:

无法创建线程中的 WebView

4

2 回答 2

2

我想出了一种解决方法,可以避免内存泄漏,但代价是存储的数据量增加了一倍。基本上资产目录的所有内容都必须复制到内部或外部存储,而 HTML 页面必须从这些存储目录加载到 WebView。

内部存储器

  • 目标目录: mContext.getFilesDir();
  • 例如。/data/data/com.package.name/files
  • HTML/CSS/Javascript 代码对用户隐藏
  • 如果卸载应用程序,代码将被删除
  • 如果 <audio> 或 <video> 标签要与 MediaPlayer 正常工作,媒体文件必须放在根目录而不是子目录中;如果放置在子目录中,文件只能通过 Javascript 使用 URL 重定向来触发 [ 例如。location.href=audioNodes.src;] 而不是播放 [ audioNodes.play(); ] 并在 WebViewClient.shouldOverrideUrlLoading 中捕获该 URL 并将其分配给 MediaPlayer 变量(子目录似乎没有以常规方式运行)。

外置储存

  • 目标目录:new File(mContext.getExternalFilesDir(STORAGE_SERVICE).getAbsolutePath());
  • 例如。/mnt/sdcard/Android/data/com.package.name/files/storage
  • 用户可以看到 HTML/CSS/Javascript 代码,揭示代码的内部工作原理
  • 需要存在 SD 卡(如果手机使用外部卡)并且没有写保护
  • 如果卸载应用程序,代码将被删除
  • 子目录中的媒体文件不需要特殊处理,将直接与 MediaPlayer 一起使用(按照惯例)

以下是将指定目录/子目录的内容从资产文件夹传输到存储(在本例中为内部)的示例方法。如果遇到子目录,会递归调用向下钻取。种子调用必须通过""作为 sourceDirName。

注意:正如所写,仅适用于深度为 1 的子目录,并且文件通过包含“。”与目录区分开来。名称和扩展名之间的字符 - 如果此测试不适合您,您可能需要使用不同的测试。不能在资产成员上使用像if (new File(sourceFileNames[i]).isDirectory())这样的测试,因为它们不是真正的文件;来自 AssetManager 文档:'文件 ... 已作为简单的字节流与应用程序捆绑在一起。'

private void copyAssetsToStorage(String sourceDirName)
{
    // /data/data/com.package.name/files
    try
    {
        String[] sourceFileNames = mContext.getAssets().list(sourceDirName);
        File     targetDir       = mContext.getFilesDir();

        if (sourceDirName != "")
        {
            sourceDirName += "/";
            targetDir      = new File(targetDir, sourceDirName);
            targetDir.mkdir();
        }

        targetDir.setReadable(true, false);
        if (sourceFileNames != null)
        {
            byte[]           buffer;
            int              length;
            InputStream      inStream;
            File             outFile;
            FileOutputStream outStream;
            for (int i = 0; i < sourceFileNames.length; i++)
            {
                if (sourceFileNames[i].contains(".") == false)
                {
                    // Recursive call to drill down
                    copyAssetsToStorage(sourceFileNames[i]);
                }
                else
                {
                    inStream  = mContext.getAssets().open(
                                sourceDirName + sourceFileNames[i]);
                    outFile   = new File(targetDir, sourceFileNames[i]);
                    outStream = new FileOutputStream(outFile, false);
                    buffer    = new byte[8192];
                    while ((length = inStream.read(buffer)) > 0)
                    {
                        outStream.write(buffer, 0, length);
                    }
                    inStream.close();
                    inStream = null;
                    outStream.flush();
                    outStream.close();
                    outStream = null;
                    outFile.setReadable(true, false);
                }
            }
        }
    }
    catch (Exception ex)
    {
        ex.printStackTrace();
    }

}   // copyAssetsToStorage
于 2012-10-16T20:21:50.913 回答
2

试试这个

WebSettings settings = webvew.getSettings();
settings.setAppCacheEnabled(false);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setDatabaseEnabled(false);
settings.setDomStorageEnabled(false);
settings.setGeolocationEnabled(false);
settings.setPluginsEnabled(false);
settings.setSaveFormData(false);
settings.setSavePassword(false);

在 webview 中加载 html 之前,我使用 loadDataWithBaseURL 而不是 loadUrl。

loadUrl 只能在您在 webview 中加载 Web 服务器时使用,否则会导致内存泄漏。

它对我有用

于 2013-05-28T13:34:45.997 回答