简体   繁体   English

在 java 中处理大字符串时,StringBuilder 内存不足错误

[英]StringBuilder out of memory error when working with large strings in java

I went from String test += str;我从String test += str; where test grew exponentially large with thousands and thousands of characters.其中test以成千上万个字符呈指数级增长。 It took 45 minutes to run, probably from creating large strings and deleting garbage.运行需要 45 分钟,可能是因为创建大字符串和删除垃圾。 I then staggered the input like this which brought it to 30 seconds.然后我像这样交错输入,使其达到 30 秒。

This seems like the cheap way to do it, but it worked well:这似乎是一种廉价的方法,但效果很好:

  if (secondDump.length() > 50)
  {
     intermedDump = intermedDump + secondDump;
     secondDump = "";
  }      

  if (intermedDump.length() > 100)
  {
     thirdDump = thirdDump + intermedDump;
     intermedDump = "";
  }
  if (thirdDump.length() > 500)
  {
     fourthDump = fourthDump + thirdDump;
     thirdDump = "";
  }
  if (fourthDump.length() > 1000)
  {
     fifthDump = fifthDump + fourthDump;
     fourthDump = "";
  }
  //with just this and not sixth.  Runtime>>>> : 77343
  if (fifthDump.length() > 5000)
  {
     sixthDump = sixthDump + fifthDump;
     fifthDump = "";
  }
  //with just this.  Runtime>>>> : 35903Runtime>>>> : 33780
  if (sixthDump.length() > 10000)
  {
     fillerDump = fillerDump + sixthDump;
     sixthDump = "";
  }

I then discovered that StringBuilder exists, and I've been trying to use it since, replacing all string operations with it.然后我发现StringBuilder存在,并且我一直在尝试使用它,用它替换所有字符串操作。

The problem is, I keep getting an java.lang.OutOfMemoryError with a java memory heap overflow.问题是,我不断收到java.lang.OutOfMemoryError和 java 内存堆溢出。 I think the string is just too long to store in memory as a StringBuilder object, because it makes about 1/50th of the progress that my previous code did before crashing with an out of memory error.我认为该字符串太长而无法作为StringBuilder对象存储在内存中,因为它的进度大约是我之前的代码在因内存不足错误而崩溃之前所做的进度的 1/50。 It's only working with maybe under a thousand characters.它只能处理可能不到一千个字符。

Why can a string hold the entire output and this can't come close?为什么一个字符串可以保存整个输出而这不能接近? Also, if I append text to JTextPane , how much memory does that need?另外,如果我将文本附加到JTextPane ,那需要多少内存? If I dump the StringBuilder contents to JTextpane and keep appending and clearing StringBuilder that doesn't seem to work either.如果我将StringBuilder内容转储到JTextpane并继续附加和清除似乎也不起作用的StringBuilder

Here is the existing code.这是现有的代码。 Page is just an object being passed: Page 只是一个被传递的对象:

protected void concatPlates(page PageA) throws IOException
{
   if (backend.isFirstPage == false)
   {
      frontend.fillOutputPane("\n                                 " +
         "                                               \n", PageA);
      frontend.fillOutputPane("                                 " +
         "                                               \n", PageA);
      frontend.fillOutputPane("                                 " +
         "                                               \n", PageA);
   }
   for (int i = 0; i < PLATELEN-1; i++)
   {

      if (arrLeftCol[i].length() == 0)
      {
         /////////////////////////////////////////////////////////
         /////////////////////////////////////////////////////////
         frontend.fillOutputPane(arrLeftCol[i].append(
           arrRightCol[i]));
      }
     else
     {
        PageA.tempStrBuff = new StringBuilder(arrLeftCol[i].substring(0,40));
        frontend.fillOutputPane(PageA.tempStrBuff.append(arrRightCol[i]));
     }
     arrLeftCol[i].append("");
     arrRightCol[i].append("");

     backend.isFirstPage = false;
  }
}


//this is the frontend class
public static void fillOutputPane(String s, page PageA)
{
   fillOutputPane(PageA.getStrBuf());
}
public static void fillOutputPane(StringBuilder stringBuild)
{
  try
  {
     str.append(stringBuild);
  }
  catch (java.lang.OutOfMemoryError e)
  {
     System.out.println((str.length() * 16) /8);
     //System.out.println(str);
     System.out.println("out of memory error");
     System.exit(0);
  }
}

Here is the error:这是错误:

Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Unknown Source)
at java.lang.AbstractStringBuilder.expandCapacity(Unknown Source)
at java.lang.AbstractStringBuilder.append(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at backend.fill(backend.java:603)
at frontend$openL.actionPerformed(frontend.java:191)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.AbstractButton.doClick(Unknown Source)
at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)

I think this is what a stack trace is:我认为这就是堆栈跟踪:

java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Unknown Source)
at frontend.fillOutputPane(frontend.java:385)
at page.concatPlates(page.java:105)
at backend.setPlate(backend.java:77)
at backend.fill(backend.java:257)
at frontend$openL.actionPerformed(frontend.java:191)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.AbstractButton.doClick(Unknown Source)
at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$2.run(Unknown Source)
at java.awt.EventQueue$2.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)81240560
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

Apparently your application doen't have enough memory for complete the operation.显然您的应用程序没有足够的内存来完成操作。 So you need to specify memory flags to your virtual machine.所以你需要为你的虚拟机指定内存标志。 You can try the following:您可以尝试以下操作:

 java -Xms256m -Xmx512m YourApp

Where:在哪里:

  • Xms minimun memory allocated by your program at startup (in the example 256 MB)您的程序在启动时分配的 Xms 最小内存(在示例中为 256 MB)
  • Xmx maximun memory allocated by your program if it need more (in the example 512 MB)如果需要更多 Xmx 由您的程序分配的最大内存(在示例中为 512 MB)

Well one of the things that might happen is the fact that in Java, java.lang.String gets special treatment.可能发生的事情之一是在 Java 中, java.lang.String 得到特殊处理。 Strings are immutable, and thus the JVM places each String object in a pool .The role of this pool, amongs others is the fact that is used as a sort of "cache" where if you create multiple String instances having the actual "text" value identical, the same instance will be reused from the pool.字符串是不可变的,因此 JVM 将每个 String 对象放在一个池中。这个池的作用是用作一种“缓存”,如果您创建多个具有实际“文本”的 String 实例值相同,将从池中重用相同的实例。 This way creating what seems to be a big number of String object instances with the same text inside will infact revert to having very few actual String instances in memory.通过这种方式,创建似乎是大量内部具有相同文本的 String 对象实例实际上将恢复到内存中只有很少的实际 String 实例。 On the other hand, if you use the same text to initialize multiple StringBuilder instances, those will actually be separate instances (containing the same text), and thus occupying more memory.另一方面,如果您使用相同的文本来初始化多个 StringBuilder 实例,这些实例实际上将是单独的实例(包含相同的文本),从而占用更多内存。

On the other hand, concatenating Strings (such as String c = "a"+"b"; ) will in fact create more object instances that if you do it with StribgBuilder (such as new StringBuilder("a").append("b"); ).另一方面,连接字符串(例如String c = "a"+"b"; )实际上会创建更多的对象实例,如果您使用 StribgBuilder(例如new StringBuilder("a").append("b"); )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM