避免 Android 中的 Java 代码生成的 JNI 错误

Avoid JNI ERROR generated by Java code in Android

我正在为我必须在 Android 中管理的数百个正则表达式开发一个测试。 我遇到了一个我无法阻止的灾难性回溯,(即匹配器进入了一个指数复杂度,它似乎处于无限循环中,而实际上,它正在探索大量可能的匹配),所以我需要限制使用超时的匹配的整体执行。

我已经找到了一种可能的方法here,但我还必须从 find() 方法中获取布尔值 return,因此 Runnable 不是最佳选择。 即使在上面 link 中其他答案中提出的微小变化,避免使用 thread 也不适用,因为它基于 CharSequence 的扩展,它根本不起作用,因为 charAt 没有在matcher.find()(检查了两次,在调试期间都使用断点并读取了 Matcher 源代码)。 Edit:我第二次发现 @NullPointerException already found 从未调用过 charAt,但我不知道如果从 3 年前他就找到了解决方案

所以,到目前为止,我发现的最佳选择似乎是使用 FutureTask,它可以指定超时,也可以 return 一个值。我实现了以下代码:

private boolean interruptMatch(final Matcher matcher){

    boolean res = false;
    ExecutorService executor = Executors.newSingleThreadExecutor();
    FutureTask<Boolean> future =
        new FutureTask(new Callable() {
            public Boolean call() {
                return matcher.find();
            }
        });
    executor.execute(future);

    try {
        res = future.get(2000, TimeUnit.MILLISECONDS);
    } catch (InterruptedException e) {
        Log.d("TESTER","Find interrupted after 2000 ms");
    } catch (ExecutionException e) {
        Log.d("TESTER","Find ExecException after 2000 ms");
    } catch (TimeoutException e) {
        Log.d("TESTER","Find timeout after 2000 ms");
    }
    future.cancel(true);
    executor.shutdownNow();
    return res;
}

这部分代码被 main 方法以几乎 "classic" 的方式调用:

pattern = Pattern.compile(pattern, java.util.regex.Pattern.CASE_INSENSITIVE);
matcher = pattern.matcher(inputString);
if (interruptMatch(matcher)) { // before the need to manage catastrophic backtracking here there was a simple if (matcher.find()){
    // Do something
}

所以,一切似乎都有效,至少对于前几百个模式(也限制了超时时间,灾难性回溯长 运行 发现),直到我收到以下错误:

JNI 错误(应用程序错误):弱全局引用 table 溢出(max=51200)

它是由上面的 java 代码生成的(在没有出现此错误之前 - 显然取消了导致灾难性回溯的模式),但我找不到如何清理全局引用table,(我发现了一些关于 JNi 代码直接生成的类似问题的答案,而不是来自 Java),而不是如何找到解决方法或其他有效方法。 EDIT: 我进一步尝试调试,发现调用get方法时出现问题。我试着按照 FutureTask 的代码,但我没有找到任何有用的东西(而且我很快就厌倦了)。

你能帮帮我吗? 提前谢谢你

经过其他挖掘,我发现Android中有一个tracked issue,(它似乎涉及其他主题,但它也回答了我的问题)并且从回复中我了解到它只是在调试过程中出现的问题。我再次测试了我的测试应用程序,我发现它是真的:没有调试上述错误不会发生。所以,这个问题的严重性要低得多,我可以忍受它(对我来说这是一个封闭的问题)–