【问题标题】:StrictMode complains about InputStream not being closedStrictMode 抱怨 InputStream 没有被关闭
【发布时间】:2012-03-19 21:41:19
【问题描述】:

我收到了StrictMode 在 Android 中报告的以下违规行为。

02-05 04:07:41.190: ERROR/StrictMode(15093): 获取资源 在附加的堆栈跟踪中,但从未释放。请参阅 java.io.Closeable 了解 有关避免资源泄漏的信息。 02-05 04:07:41.190: 错误/严格模式(15093):java.lang.Throwable:显式终止 未调用方法“关闭”

这是在抱怨没有正确关闭流。但是,不应该关闭in 关闭底层流吗?标记错误的原因可能是什么?

    private ArrayList<Uri> loadPath() {
        ArrayList<Uri> uris = new ArrayList<Uri>();
        if (mFile.exists()) {
            ObjectInputStream in = null;
            try {
                in = new ObjectInputStream(new BufferedInputStream(
                         new FileInputStream(mFile), STREAM_BUFFER_SIZE));
                ArrayList<String> strings = new ArrayList<String>();
                strings.addAll((ArrayList<String>) in.readObject());
                for (String string : strings) {
                    uris.add(Uri.parse(string));
                }
            } catch (Exception e) {
                mFile.delete();
            } finally {
                IOUtils.closeQuietly(in);
            }
        }
        return uris;
     }

    public static void closeQuietly(InputStream input) {
        try {
            if (input != null) {
                input.close();
            }
        } catch (IOException ioe) {
            // ignore
        }
    }

【问题讨论】:

  • 不确定 StrictMode 检查器有多聪明,但它看起来被您的延迟关闭弄糊涂了,即使用实用程序关闭您的为您直播。
  • 在我的情况下,即使close()finally 子句中内联,我也会收到此错误。

标签: java android objectinputstream android-strictmode


【解决方案1】:
in = new ObjectInputStream(new BufferedInputStream(
                         new FileInputStream(mFile), STREAM_BUFFER_SIZE));

在此代码示例中,您仅关闭 ObjectInputStream 而不是 BufferedInputStreamFileInputStream,您需要将它们全部关闭。

【讨论】:

  • 你呢?这与康斯坦丁·索洛马托夫的回答相矛盾。
  • @GrahamBorland 只需对其进行测试,您就会看到。
【解决方案2】:

查看源代码,ObjectInputStreamBufferedInputStream 的构造函数都可以抛出异常,这将导致在下一行分配 FileInputStream 对象,但 in 变量仍将为空:

            in = new ObjectInputStream(
                    new BufferedInputStream(
                            new FileInputStream(mFile), 
                    STREAM_BUFFER_SIZE)
            );

由于当我们到达finally 块时in 为空,打开的FileInputStream 对象不会被您的closeQuietly() 方法关闭,导致StrictMode 最终抱怨:)

我建议的最简单的解决方法是将分配分成 3 个变量并在每个变量上调用 closeQuietly(),可能是这样的:

private ArrayList<Uri> loadPath() {
    final ArrayList<Uri> uris = new ArrayList<Uri>();
    if (mFile.exists()) {
        ObjectInputStream ois = null;
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            fis = new FileInputStream(mFile);
            bis = new BufferedInputStream(fis, STREAM_BUFFER_SIZE);
            ois = new ObjectInputStream(bis);
            final ArrayList<String> strings = new ArrayList<String>();
            strings.addAll((ArrayList<String>) ois.readObject());
            for (final String string : strings) {
                uris.add(Uri.parse(string));
            }
        } catch (final Exception e) {
            mFile.delete();
        } finally {
            closeQuietly(fis);
            closeQuietly(bis);
            closeQuietly(ois);
        }
    }
    return uris;
}

【讨论】:

  • 很好发现,但在我的情况下没有发生异常。 (我会回去仔细检查以绝对确定。)
  • 也许我在这里错了,但 StrictMode 不也抱怨“可能的场景”吗?例如,它抱怨来自主线程的 IO 访问,即使实际上没有导致 ANR。
  • 它应该抱怨实际发生的事情。在主线程上进行 IO 访问的情况下,主线程上确实发生了 IO 访问。 (这不仅仅是理论上的。)所以,如果 InputStream 真的泄漏了,它应该只抱怨 InputStream 泄漏。
  • 您会因在 OP 代码中发现可能导致泄漏的真正问题而获得奖励。我不是 OP,我自己的代码非常相似,但略有不同,我仍然需要完全了解它。
  • 谢谢!如果您也需要帮助找出代码中的问题,从这里添加一个指向它的链接很可能也会增加几组新的眼睛来查看它:)
【解决方案3】:

代码应该可以工作,除非您使用的 ProGuard 可能会弄乱字节码。

FileInputStream 具有到 CloseGuard 的挂钩,如果实例已关闭,则会在 finalize() 中检查。这就是为什么我认为它应该工作。问题是天气close() 是否被调用?

我认为 FileInputStream 已创建(因为 StrictMode 引发了异常),但最终引发了异常并在某处被忽略。

    try {
        if (input != null) {
            input.close();
        }
    } catch (Exception ioe) {
        // check exception here
    }

【讨论】:

    【解决方案4】:

    如果您查看 ObjectOutpuStream 源代码,您会看到它的 close 方法关闭了底层流。与许多其他代码分析工具一样,Android 的严格模式具有误报,您可以忽略或重写代码以使其不会抱怨(内联 closeQuietly 方法)。

    【讨论】:

    • Android 的 StrictMode 不是代码分析工具。它在源代码中实现,请查看FileInputStreamCloseGuard 中的finalize()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-13
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 2011-05-11
    相关资源
    最近更新 更多