【问题标题】:Android Webview JNI ERROR with loadUrl带有 loadUrl 的 Android Webview JNI 错误
【发布时间】:2013-08-24 19:10:36
【问题描述】:

我正在编写一个 Android 应用程序,它正在打开一个本地存储的 html 文件 check.html。这个 html 文件显示了一些不错的文本,然后 http 转发到我真正想要的网页。现在可能会发生服务器已关闭,甚至网络已断开,但我希望应用程序一直尝试访问它。

如果只是服务器宕机,Android在返回onReceivedError()之前请求网页时会有一些延迟,所以我没有问题,但是如果网络被拔掉,它会立即返回。

1 到 2 分钟后,我的应用崩溃了:

08-22 14:17:47.382: D/dalvikvm(8337): GC_CONCURRENT 释放 178K,3% 释放 12530K/12807K,暂停 0ms+7ms
08-22 14:17:57.572: D/dalvikvm(8337): GC_CONCURRENT 释放 235K,3% 释放 14253K/14599K,暂停 0ms+7ms
08-22 14:18:07.882: D/dalvikvm(8337): GC_CONCURRENT 释放 241K,3% 释放 15969K/16327K,暂停 0ms+10ms
08-22 14:18:17.717: D/dalvikvm(8337): GC_CONCURRENT 释放 237K,2% 释放 17717K/18055K,暂停 0ms+13ms
08-22 14:18:28.757: D/dalvikvm(8337): GC_CONCURRENT 释放 249K,2% 释放 19468K/19783K,暂停 3ms+3ms
08-22 14:18:39.105: D/dalvikvm(8337): GC_CONCURRENT 释放 241K,2% 释放 21185K/21511K,暂停 4ms+10ms
08-22 14:18:49.008: D/dalvikvm(8337): GC_CONCURRENT 释放 238K,2% 释放 22900K/23239K,暂停 0ms+10ms
08-22 14:18:51.157: E/dalvikvm(8337): JNI ERROR (app bug): local reference table overflow (max=512)
08-22 14:18:51.157: W/dalvikvm(8337): JNI 本地参考表 (0x1729e78) 转储:
08-22 14:18:51.157:W/dalvikvm(8337):最后 10 个条目(共 512 个):
08-22 14:18:51.157: W/dalvikvm(8337): 511: 0x410dec88 android.content.res.AssetManager
08-22 14:18:51.157: W/dalvikvm(8337): 510: 0x4215db30 byte[] (32768 个元素)
08-22 14:18:51.157: W/dalvikvm(8337): 509: 0x42155b18 byte[] (32768 个元素)
08-22 14:18:51.158: E/dalvikvm(8337): 添加到 JNI 本地引用表失败(有 512 个条目)

代码如下:

mWebView = (WebView) findViewById(R.id.webView);
mWebView.setWebChromeClient(new KB_WebChromeClient(this));
mWebView.setWebViewClient(new KB_WebViewClient());
mWebView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
mWebView.clearCache(true);
mWebView.clearHistory();
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
mWebView.addJavascriptInterface(new WebAppInterface(this, this), "Android");

mWebView.loadUrl("file:///android_asset/check.html");

WebViewClient 的代码如下:

public class KB_WebViewClient extends WebViewClient {

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        view.clearCache(true);
    }

    @Override
    public void onReceivedError (WebView view, int errorCode, String description, String failingUrl)
    {
        view.loadUrl("file:///android_asset/check.html");
    }
}

基本上,check.html页面被加载,onPageFinished被调用,然后html转发到另一个页面,这不起作用,所以onReceivedError被调用,它将再次开始加载check.html aso .

在我的研究中我找到了SO: Android Expand JNI Local Reference Table,答案是

您需要删除对类和对象的本地引用。

这是什么意思,我的问题在哪里? webview.loadUrl 是否会创建任何复杂的东西并且垃圾收集器不够快而无法清理?我不是一直都在创建 WebView,这到底是怎么回事?

提前感谢您的帮助!

编辑:我实现了一个计数器来计算 webview.loadUrl 被调用的频率。在应用程序崩溃之前,它计数 280 到 290。我试图删除 check.html 并在网络中加载我想要的网页,然后尝试次数达到 570 次才崩溃。它接缝,每个网页加载都被计算在内,即使它是从 HTML 页面完成的。我正在查看系统的堆,我看到的是,每次完成一个循环时,都会分配 1 到 3 个 byte[] 数组,大小为 32kB,但未释放。即使是垃圾收集也没有释放它。我会尝试每 x 次尝试摆脱 Webview。也许这种解决方法可以工作......

编辑:link 下,它们显示存在错误:

external/webkit/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp 好像有泄漏。

如果 (!m_buffer) {
m_buffer = env->NewByteArray(out->capacity());
m_buffer = (jbyteArray) env->NewGlobalRef(m_buffer);
}

本地引用由 NewByteArray 创建,但不会被删除。

我认为这可能与我的问题有关。我正在运行 Android 4.0.3 并且无法更新,因为他们似乎解决了这个问题....好吧,我会尝试找到解决方法。

【问题讨论】:

    标签: java android memory webview java-native-interface


    【解决方案1】:

    据我了解,Android 的 WebView 在加载页面时会发生内存泄漏(请参阅问题编辑链接)。人们可能会想到一种解决方法是销毁 WebView。它可以工作,但由于某种原因,WebView 不能被销毁(至少 GC 不能清理它),因为它链接到 Activity。 解决方案是多次尝试后销毁 Activity。我决定在每 150 次尝试后进行一次。

    WebViewClient:

    @Override
    public void onReceivedError (WebView view, int errorCode, String description, String failingUrl)
    {
        counter++;
        if(150 == counter){
            mainActivity.KillThisThenStartNewOne();
        }
        view.loadUrl("file:///android_asset/check.html");
    }
    

    活动:

    public void KillThisThenStartNewOne(){
         Intent intent = new Intent(this.getApplicationContext(), MainActivity.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);  
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            this.getApplicationContext().startActivity(intent);
            //for restarting the Activity
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(0);
    }
    

    在 Android 4.0.3 上测试并且可以工作。 Activity的重启大约需要0.5到1秒。

    【讨论】:

    • 我和你有同样的问题。但我不知道如何解决这个问题。我只是使用 WebView 来加载几个(很多)html 文件。不是 NDK,不是 jni。如何修复这个错误?你能给我一些帮助吗?
    • 在我的应用程序中,我只是加载本地 html 文件。不是来自互联网。我也有同样的问题。就我而言,永远不会调用 onReceivedError 。我不知道您的解决方法是否是一个不错的选择。
    • 我该如何解决这个问题?我的 webview 需要加载太多的本地 html 文件。
    • 首先,请不要在 cmets 这里发送垃圾邮件!我的解决方案适用于如果您不断尝试打开一段时间离线的页面并且在在线时间您通常不会重新加载页面的情况。这意味着,在线时对该页面有 1 次调用,而在离线时有许多调用。这就是为什么我登陆 onReceivedError() 并且可以在那里数。为了更好的处理,我也应该计入在线案例,但没有必要。要解决您的问题,只需计算您调用页面的频率并每隔 x 调用一次 KillThisThenStartNewOne(在我的情况下,我每 150 次调用一次)
    【解决方案2】:
        public void onReceivedError (WebView view, int errorCode, String description, String failingUrl)
        {
            view.loadUrl("file:///android_asset/check.html");
        }
    

    我猜你这样做的速度很快,在一种循环中。创建一个处理程序并将其延迟发布在(一个)处理程序上可能会解决这个问题。比如:

    private Handler handler = new Handler();
    
    @Override
    public void onReceivedError (final WebView view, int errorCode, String description, String failingUrl) {
    
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                 if (view != null && view.isActivated()) {
                         view.loadUrl("file:///android_asset/check.html");
                 }
            }
        }, 500);
    }
    

    我认为您在这 1-2 分钟内完成了 10000 次 url 加载,现在您将每 0.5 秒执行一次检查,您的应用会更喜欢这样,并且不会再崩溃了。

    【讨论】:

    • 所以你会说,我的问题是尝试的速度(在没有网络连接的情况下,每次尝试都需要 500 毫秒)并且系统太慢而无法处理我的垃圾?我可以等待 10 秒没有问题,但我担心我的问题只是推迟到假设 4 小时处理以下崩溃......
    • 是的,尝试的速度。放一条日志语句并检查:如果您在几秒钟内进入 onReceivedError 方法 100 次,那么这一定是问题所在。你的循环可能会阻塞整个系统。
    • 我放入了一个计数器,用于计算尝试次数并将其显示给我。就像我说的,每次尝试已经花费了大约 500 毫秒,并且在计数 280 之后它崩溃了。所以我敢打赌,即使我等待 10 秒,在这 280 +- x 次尝试之后我也会遇到问题。
    • 啊,我看你的回复太快了。好的。 ping 服务器(在您的 web 视图之外)并仅在服务器响应时更新 web 视图,可能是一种选择。祝你好运。
    • @Frank 我也有这个严重的问题。我需要有人给我一些帮助。 Micky 的解决方法似乎对我不起作用。该应用仍会出现“JNI ReferenceTable overflow (max=512)”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    相关资源
    最近更新 更多