在Java

时间:2016-08-19 15:51:33

标签: java string memory memory-management

在我的程序中,主要逻辑是用不同的方法构造字符串,然后按文件中的特定顺序保存它们。但是我的内存消耗非常高,所以我想知道如何在内存中保存更少的字符串。因此,我将尝试简化程序,以便于阅读。我的小字符串生成方法如下:

然后我的主要逻辑是:

        BufferedWriter bw = new BufferedWriter(fw);
        for(int i=1;i<1_000_000_000;i++){
            bw.write(processMethod(i));
        }
        bw.close();

processMethod是一种调用generateTag m 次方法的方法,使用StringBuilder制作字符串,然后保存到BufferedWriter

public static String generateTag(final String tagName, final String name, final String value) {
        StringBuilder attribute = new StringBuilder();
        attribute.append("<tag:");
        attribute.append(tagName);
        attribute.append(" name=\"");
        attribute.append(name);
        attribute.append("\">");
        attribute.append(value);
        attribute.append("</tag:");
        attribute.append(tagName);
        attribute.append(">");
        return attribute.toString();
    }

因此,当我开始processMethod执行 1_000_000_000 次,然后m次被称为generateTag方法。我在内存中有 1_000_000_000 * m 个字符串。我怎样才能轻松删除他们的作品?我想像是这样的事情:

public static String generateTag(final String tagName, final String name, final String value, final BufferedWriter bf) {
   ....
   bf.write(someBuilder.toString());
   ..

}

但是我认为通过BufferedWriter并不是一件好事。 你能否建议我少一些String创建的描述。

enter image description here

enter image description here

3 个答案:

答案 0 :(得分:4)

如果你的程序确实只是一个接一个地调用方法并且那些方法生成字符串并且这些字符串按照它们生成的顺序写入文件,那么使用main直接写入文件会更简单BufferedWriter

try (BufferedWriter bw = new BufferedWriter(fw);) {
    for(int i=1;i<1_000_000_000;i++){
        processMethod(i, bw);
    }
}

(请注意,我使用try-with-resources自动关闭缓冲的编写器。)

然后当processMethod调用generateTag时,它会将缓冲的编写者传递给它:

public void processMethod(int i, BufferedWriter bw) {
    ...
    generateTag(...,bw);
    ...
}

generateTag将成为:

public static void generateTag(final String tagName, final String name, final String value, final BufferedWriter bw) {
        bw.write("<tag:");
        bw.write(tagName);
        bw.write(" name=\"");
        bw.write(name);
        bw.write("\">");
        bw.write(value);
        bw.write("</tag:");
        bw.write(tagName);
        bw.write(">");
    }

由于BufferedWriter被缓冲,这意味着每次调用write时都不会有磁盘访问,但每次缓冲区都被填满时。因此,这不会让您节省磁盘访问速度。但它会为你节省所有的记忆。

当然,如果你不按顺序写结果,或者一种方法的结果取决于另一种方法的结果,那么你需要修改它,但是,你应该尽快写出来准备下一段String

答案 1 :(得分:1)

您可以考虑的一件事是不要将它们保存在内存中,而是尽快写出来......

许多XML api就像jdom,dom和dom4j一样,有助于在内存中构建树模型的有害习惯,而实际上,将字节转储到输出缓冲区的效率要高得多...

您可以重写您的方法以包含输出流变量,并使用输出流清除所有字节。

答案 2 :(得分:1)

使用Appendable抽象确保generateTag(如果您愿意,同样processMethod)与BufferedWriter无关。事实上,我们甚至可以通过StringBuilder来做与以前相同的功能,我们可以使用它来提供适当的重载:

public static CharSequence generateTag(
    final String tagName, final String name, final String value) {

    StringBuilder attribute=new StringBuilder(80);
    try { generateTag(tagName, name, value, attribute); }
    catch (IOException ex) { throw new AssertionError(ex); }
    return attribute;
}
public static void generateTag(
    final String tagName, final String name, final String value, Appendable attribute)
    throws IOException {

    attribute.append("<tag:");
    attribute.append(tagName);
    attribute.append(" name=\"");
    attribute.append(name);
    attribute.append("\">");
    attribute.append(value);
    attribute.append("</tag:");
    attribute.append(tagName);
    attribute.append(">");
}

请注意,重载返回CharSequence而不是String,以便能够省略最后的StringBuilder.toString()复制步骤。不幸的是,鉴于current implementation,使用append(CharSequence)调用BufferedWriter将无法获得回报。还有APIs allowing to use CharSequence directly