【问题标题】:StringBuilder - java.lang.OutOfMemoryError: Java heap spaceStringBuilder - java.lang.OutOfMemoryError:Java 堆空间
【发布时间】:2019-12-12 02:36:31
【问题描述】:

下面的代码会生成 OOM 错误,而我只附加到现有的 StringBuilder。请解释为什么会生成 OOM,因为我没有为每个递归创建任何新对象。

object BeerSong {

  val song = StringBuilder.newBuilder
  var count = 0
  def recite(start : Int, end : Int): String = {
      start match {
        case 1 => song.append(s"$start bottles of beer on the wall, $start bottles of beer.\nTake one down and pass it around, no more bottles of beer on the wall.\n")
        case 0 => song.append("No more bottles of beer on the wall, no more bottles of beer. Go to the store and buy some more, 99 bottles of beer on the wall.")
        case _ => song.append(s"$start bottles of beer on the wall, $start bottles of beer.\nTake one down and pass it around, ${start.toInt - 1} bottles of beer on the wall.\n")
      }
    count += 1
      if (count == end) {
            song.toString()
      }
      recite(start -1, end)
  }

【问题讨论】:

标签: scala out-of-memory


【解决方案1】:

尽管您只附加到单个StringBuilder,但当达到当前容量时,内部将在堆上分配具有更大容量的新数组。请注意错误消息如何指示调用Arrays.copyOf

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3332)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)

您的代码可能存在两个问题。 texasbruce 已经解释了一个关于缺少递归退出点的问题。另一个可能是关于count 变量的行为。尝试将其初始化为等于 start 值,然后递减它

val start = 100
var count = start
...
count -= 1

而不是增加它

var count = 0
...
count += 1

事实上,我们可以将count 变量放在一起。试试下面的例子

object Example extends App {
  val song = StringBuilder.newBuilder
  def recite(start : Int, end : Int): String = {
    start match {
      case 1 => song.append(s"$start bottles of beer on the wall, $start bottles of beer.\nTake one down and pass it around, no more bottles of beer on the wall.\n")
      case 0 => song.append("No more bottles of beer on the wall, no more bottles of beer. Go to the store and buy some more, 99 bottles of beer on the wall.")
      case _ => song.append(s"$start bottles of beer on the wall, $start bottles of beer.\nTake one down and pass it around, ${start.toInt - 1} bottles of beer on the wall.\n")
    }
    if (start == end) {
      song.toString()
    }
    else recite(start - 1, end)
  }

  println(recite(100, 0))
}

哪个输出

100 bottles of beer on the wall, 100 bottles of beer.
Take one down and pass it around, 99 bottles of beer on the wall.
99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 98 bottles of beer on the wall.
98 bottles of beer on the wall, 98 bottles of beer.
...
3 bottles of beer on the wall, 3 bottles of beer.
Take one down and pass it around, 2 bottles of beer on the wall.
2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottles of beer on the wall.
1 bottles of beer on the wall, 1 bottles of beer.
Take one down and pass it around, no more bottles of beer on the wall.
No more bottles of beer on the wall, no more bottles of beer. Go to the store and buy some more, 99 bottles of beer on the wall.

注意我们如何使用start == end 作为退出条件。

【讨论】:

    【解决方案2】:

    您的递归函数没有结束条件。当您将歌曲兑换成字符串时,您应该结束它。否则继续递归:

      if (count >= end) {
            song.toString()
      }
      else {
            recite(start -1, end)
      }
    

    【讨论】:

    • 异常或错误导致运行中止:Java 堆空间 java.lang.OutOfMemoryError:Java 堆空间在 java.util.Arrays.copyOf(Arrays.java:3332) 在 java.lang。 AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137) at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:421) at java.lang.StringBuilder.append(StringBuilder .java:136) 在 scala.collection.mutable.StringBuilder.append(StringBuilder.scala:210) 在 BeerSong$.recite(BeerSong.scala:26)
    猜你喜欢
    • 2010-12-08
    • 2015-05-14
    • 2019-07-10
    • 2015-04-24
    相关资源
    最近更新 更多