java - 循环StringBuilder内存泄漏

标签 java memory-leaks stringbuilder

对于我的数据结构类(class)中的一个项目,我们必须使用广度优先和深度优先遍历来遍历图。在这种情况下,深度优先遍历的长度通常在 1 到 100,000 个节点之间。

每个节点的内容是一个字符串。遍历图表并找到解决方案并不是一个大问题。但是,一旦遍历完成,就必须显示出来。

为此,我返回每个节点的父节点,并将节点的字符串添加到堆栈中。此时代码仍然运行良好(据我所知)。当尝试显示这些字符串时,速度会大幅下降。

给定一堆数万个字符串,如何显示它们?直接调用 System.out.println() 花费的时间太长。然而,迭代地使用 StringBuilder 只会消耗内存。我尝试以相当任意的间隔(以相当粗制滥造的方式)清除 StringBuilder,这似乎有点帮助。另外,小睡一会儿似乎也有帮助。不管怎样,当函数完成打印时,要么 Java 内存不足,要么速度极其缓慢且无响应。

有什么方法可以重构这段代码,以相对及时的方式输出所有字符串(大约 10 秒不应该要求太多),而不会使虚拟机崩溃?

if(DFSResult.hash().equals(myPuzzle.answerHash()))
{
  System.out.println("Success");
  int depth = 0;
  while(DFSResult.parent != null)
  {
    depth++;
    if(in.equals("y")) dfs.push(DFSResult.hash());
    DFSResult = DFSResult.parent;
  }
  System.out.println("found at a depth of "+depth+"\n\n");
  StringBuilder s = new StringBuilder();
  int x = 0;
  boolean isSure = false;
  if(in.equals("y"))
  {
    System.out.println("Are you really sure you want to print out a lineage this long? (y/n)");
    try{
      if(input.readLine().toLowerCase().equals("y"))isSure = true;
    }catch (Exception e) {
    }//
  }
  s = new StringBuilder();
  while(!dfs.empty() && isSure)
  {
    //System.out.println(dfs.pop());
    s.append(dfs.pop()).append("\n");
    x++;
    if(x % 500 == 0)
    {//Flush the stringbuilder
      try{Thread.sleep(50);}catch(Exception e){e.printStackTrace();}
      System.out.println(s.toString());
      s.delete(0,s.length());//supposed 25% efficiency increase over saying s = new StringBuilder()
    }
  }
  System.out.println(s.toString());

最佳答案

您不需要在示例中使用 StringBuilder。 相反,只需这样做:

System.out.println(dfs.pop());

在你的循环中。也不需要 sleep 。循环内只有一行。

System.out.println()效率没有问题。请考虑以下代码:

public class TestMain {
  public static void main(String[] args) {
    long timeBefore = System.currentTimeMillis();
    for (int i = 0; i < 50000; i++) {
        System.out.println("Value = " + i);
    }
    long timeAfter = System.currentTimeMillis();
    System.out.println("Time elapsed (ms): " + (timeAfter - timeBefore));
  }
}

这是我机器上的最后几行输出:

. . .
Value = 49994
Value = 49995
Value = 49996
Value = 49997
Value = 49998
Value = 49999
Time elapsed (ms): 538

如您所见,速度非常快。问题不在于 println() 方法。

下面的堆栈使用示例:

public static void main(String[] args) {
    long timeBefore1 = System.currentTimeMillis();
    Stack<String> s = new Stack<String>();
    for (int i = 0; i < 50000; i++) {
        s.push("Value = " + i);
    }
    long timeAfter1 = System.currentTimeMillis();
    long timeBefore2 = System.currentTimeMillis();
    while (!s.isEmpty()) {
        System.out.println(s.pop());
    }
    long timeAfter2 = System.currentTimeMillis();
    System.out.println("Time spent on building stack (ms): " + (timeAfter1 - timeBefore1));
    System.out.println("Time spent on reading stack (ms): " + (timeAfter2 - timeBefore2));
}

输出:

. . .
Value = 2
Value = 1
Value = 0
Time spent on building stack (ms): 31
Time spent on reading stack (ms): 551

关于java - 循环StringBuilder内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20385357/

相关文章:

java.nio.charset.IllegalCharsetNameException : Windows-1252/WinLatin 1

c - 最小的 bison/flex 生成的代码有内存泄漏

variables - 声明变量内存泄漏

c# - LINQ - 向数据上下文添加函数

java - 在这种情况下,编译器中实际发生了什么

java - 自定义 'String' 类

java - 线程 "main"javax.ws.rs.NotAllowedException : HTTP 405 Method Not Allowed中的@POST异常

java - 用于检查已使用文件的 Windows 工具(通过 Java OSGi 进程)

java - 由于 'java.io.FileNotFoundException',检测运行失败

ios - 内存泄漏 Xcode 8 仪器