【问题标题】:BufferedWriter buffer size and occupied memoryBufferedWriter 缓冲区大小和占用内存
【发布时间】:2017-09-29 07:25:59
【问题描述】:

我正在使用 BufferedWriter 将文本写入 Java 文件。但是,我在构造函数中提供了自定义缓冲区大小。问题是,它以我给出的任何大小的块写入文件(例如,如果我将缓冲区大小设为 8KB,则文件写入一次为 8KB)。但是,当我查看 bufferedwriter 对象(使用 YourKit 分析器)占用的内存时,它实际上是给定缓冲区大小的两倍(在本例中为 16KB)。

我试图查看内部实现以了解为什么会发生这种情况,我发现它正在创建一个具有给定大小的 char 数组。而且当它写入数组时,它占用两倍的缓冲区大小是有意义的,因为每个 char 占用 2 个字节。

我的问题是,在这种情况下,BufferedWriter 是如何管理只写入 8KB 的,它在缓冲区中存储了 16KB。这在技术上正确吗?因为每次它只刷新 8KB(一半),即使它有 16KB 的缓冲区。

【问题讨论】:

    标签: java bufferedwriter


    【解决方案1】:

    但我希望存储在 char 数组中的所有字符在达到缓冲区大小(在我给定的示例中为 16 KB)时都写入文件。

    8K 的字符占用 16 KB 的内存。正确。

    现在让我们假设这些字符实际上都在 ASCII 子集中。

    当您在 Java 中将字符流写入输出文件时,字符会根据某种编码方案被编码为字节流。 (例如,此编码由 OutputStreamWriter 类中的内容执行。)

    当您使用 8 位字符集/编码方案(例如 ASCII 或 Latin-1 ... 或 UTF-8 (!!) ... 每个字符编码为 1 个字节)对这 8K 个字符进行编码时。因此,刷新包含 那些 8K 字符的缓冲区会生成 8K 字节写入。

    【讨论】:

    • 感谢@Stephen C。现在有了更好的洞察力
    【解决方案2】:

    BufferedWriter 的大小是 char 数组大小。

    public BufferedWriter(Writer out, int sz) {
        super(out);
        if (sz <= 0)
            throw new IllegalArgumentException("Buffer size <= 0");
        this.out = out;
        cb = new char[sz];
        nChars = sz;
        nextChar = 0;
    
        lineSeparator = java.security.AccessController.doPrivileged(
            new sun.security.action.GetPropertyAction("line.separator"));
    }
    

    单个字符不等于单个字节。这一切都由您的字符编码定义。

    因此,要完全按照您的描述执行任务,您必须切换到另一个类:BufferedOutputStream,其内部缓冲区完全按字节数计算。

    public BufferedOutputStream(OutputStream out, int size) {
        super(out);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }
    

    【讨论】:

    • 谢谢 Alex。我明白单字符不是单字节。但是我希望存储在 char 数组中的所有字符在达到缓冲区大小时都被写入文件(在我给定的示例中为 16 KB,因为 char 数组占用 16 KB)。但为什么没有发生呢?为什么它只将 8 KB 刷新到文件中?请帮我理解
    • 这取决于您的文件编码。 Java 使用 UTF-16 作为其内部字符存储,这意味着对于每个字符,它使用 2 个字节来存储。但是,如果您的字符只是 ASCII 并且您的文件编码是 UTF-8,那么每个字符将只使用文件中的 1 个字节,因此是结果。
    • 同意@Alex。见stackoverflow.com/questions/7019504/…。您有 1) chars 的内部存储器表示 2) bufferedWriter 内的 char 缓冲区,3) char 到字节的转换(它本身也可能使用 bytes[] 的内部缓冲区),并且每个 char 产生可变数量的字节。这弥补了复杂的内存使用预测。鸟瞰,ch​​ar 缓冲区大小的 2 到 4 倍似乎是合理的。但最终,8 个字符可能最终会将 8 个字节写入文件。或者 16. 或者 10...
    • 谢谢@Alex。我现在明白编码是成功的
    【解决方案3】:

    这取决于用于写入文件的编码:ISO-8859-1 将字符存储为单个字节,UTF-8 将所有 ASCII 字符编码为单个字节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-08
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 1970-01-01
      • 2013-12-10
      • 1970-01-01
      相关资源
      最近更新 更多