【问题标题】:Java alternatives with toString conversion from StringBuilder从 StringBuilder 进行 toString 转换的 Java 替代方案
【发布时间】:2012-07-08 19:18:20
【问题描述】:

我有这段代码可以将 StringBuilders 的 ArrayList 转换为 Strings 的 ArrayList:

代码:

public ArrayList<String> convGenSeqToString(ArrayList<StringBuilder> buff){
        ArrayList<String> convBuf = new ArrayList<String>();
        
        for (StringBuilder xVar: buff){
            convBuf.add(xVar.toString());
        }
        return convBuf;
    }

我的代码适用于 15-20MB 文本文件的文件。但是我有一个 44MB 的文本文件,每当我使用该文本文件运行程序时,我总是会收到此错误。

错误:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:2746)
    at java.util.ArrayList.ensureCapacity(ArrayList.java:187)
    at java.util.ArrayList.add(ArrayList.java:378)
    at Recognition.convGenSeqToString(Recognition.java:157)
    at Recognition.genSeq(Recognition.java:145)
    at Recognition.Recognitions(Recognition.java:96)
    at ChainDetection.main(Detection.java:25)

我已经使用 -Xmx2048M 增加了 JVM 运行配置中的内存,但我仍然有同样的错误。我在上面显示的代码中指出了错误,并突出显示了这一行:

convBuf.add(xVar.toString());

有没有其他方法可以在不使用.toString() 方法的情况下将StringBuilder 转换为字符串?我在其他论坛和这里也看到他们为 toString 创建了自定义类,但还不熟悉泛型和一些“@”关键字。有人对如何解决这个问题有建议或指导吗?

已编辑

我按照 vanza 的建议编辑了我的代码 在这里:

public ArrayList<String> convGenSeqToString(ArrayList<StringBuilder> buff){
        ArrayList<String> convBuf = new ArrayList<String>(buff.size());
        Iterator <StringBuilder> iterBuf = buff.iterator();
        
        while (iterBuf.hasNext()){
            StringBuilder x = iterBuf.next();
            convBuf.add(x.toString());
            iterBuf.remove();
        }
        return convBuf;
    }

错误信息:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.ArrayList.<init>(ArrayList.java:132)
    at Recognition.convGenSeqToString(Recognition.java:154)
    at Recognition.genSeq(Recognition.java:145)
    at Recognition.Recognitions(Recognition.java:96)
    at ChainDetection.main(ChainDetection.java:25)

我用 buff.size() 和没有 buff.size() 试过这个,我得到了同样的错误信息。但似乎我的错误信息现在减少到 5。对此还有其他想法吗?提前致谢!

【问题讨论】:

  • 为什么不用CharSequence 类型呢? toString() 没有必要。
  • 你可以用正确的大小声明你的数组列表以避免数组复制。
  • 我有点好奇为什么你有一个StringBuilders 的数组。是否有某些原因需要将元素保留为 StringBuilders?换句话说,无论函数创建这个 StringBuilders 数组,为什么不直接使用 StringBuilder 的 toString 方法创建一个 Strings 数组?
  • 实际上我的原始代码只是字符串,但是当我运行这个文本文件时,我遇到了所有这些错误。我尝试在网上搜索解决方案,发现与普通字符串连接相比,stringbuilder 在处理字符串连接方面要好得多。所以我把我的代码改成了stringbuilder,但是问题依然存在,和string有关。

标签: java string memory stringbuilder


【解决方案1】:

在不了解您的程序的情况下,我将避免对您采用的方法进行任何 cmet,并且仅对您发布的代码发表评论。不过,一个 44MB 的文件填充了一个 2G 的堆,这对我来说听起来很奇怪。

您可以做的一件事是预先在目标数组中分配空间:

ArrayList<String> convBuf = new ArrayList<String>(buf.size());

这将避免 ArrayList 调整大小步骤,该步骤会创建现有列表的副本(并显示在您的堆栈跟踪中)。

您可以尝试的另一件事是在构建 String 数组时释放对原始 StringBuilders 的引用。使用迭代器(而不是“for each”循环),并在每次迭代时使用Iterator.remove()buff 数组中删除StringBuilder;这样,如果内存不足,您将释放一些内存供垃圾收集器回收。

但是再一次,你用这么小的文件耗尽内存听起来很奇怪。也许用 jvisualvm 查看你的堆可以提供一些启示。

【讨论】:

  • 您好,感谢您的回答,我正在尝试生成一个字符序列矩阵。如果您熟悉马尔可夫链,那就是我正在尝试做的事情,并且我为序列生成的文本文件大约为 15-20MB。我会尝试你的建议,我会发布我得到的。
  • 您好,根据您的建议,我对代码进行了更新。但我仍然收到一条错误消息。
  • @dimas:是时候启动 jvisualvm 并开始寻找正在使用所有堆的东西了。
【解决方案2】:

有两种方法可以从 StringBuilder 中获取价值

  1. 首先使用Reflection并调用package protected方法 getValue() 这很难,我认为这不是很好。
  2. 二次调用方法getChars

顺便说一句,您将拥有字符数组,并且为了使用string,您将创建新的字符串实例,它将使用您的内存。

【讨论】:

    猜你喜欢
    • 2015-12-18
    • 1970-01-01
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-17
    • 2012-07-26
    相关资源
    最近更新 更多