我不明白为什么分割一个Stream[String]会产生一个GC overhead limit exceeded,这取决于Stream[String].flatMap{string => str.split(" ")}中的str是不变量的还是随机发出的。
当str不变时,就不会发生开销,而是在随机情况下发生。
我不引用循环块中的对象。
我使用def来声明Streams,以产生不累积的Streams.
谢谢你的洞察力。
这是我的密码:
import scala.util.Random
object DataOps{
val randomGen:Random = new Random()
def randomText:String = (0 to 300).map(x => randomGen.nextString(10)).mkString(" ")
val text:String = Array.fill(300)(randomGen.nextString(10)).mkString(" ")
//return a stream of strind using the same 'txt:String'
def infiniteInvariantDataStream(cnt:Int): Stream[String] = {
if (cnt>0) text#::infiniteInvariantDataStream(cnt-1)
else Stream[String]()
}
//return a Stream of random string
def infiniteDataStream(cnt:Int):Stream[String] = {
if (cnt>0) randomText#::infiniteDataStream(cnt-1)
else Stream[String]()
}
}
object BasicOps{
def dummyStringStreamSplit(datastream: Stream[String]) = {
datastream
.flatMap(txt => txt.split(" "))
.foreach(word => word)
}
}
object scalaOverflow extends App{
val n_lines:Int = 1000000
println("splitting looping over invariant text")
def datastream1:Stream[String] = DataOps.infiniteInvariantDataStream(n_lines)
BasicOps.dummyStringStreamSplit(datastream1)
println("INVARIANT LINE SPLIT OK: no heap overflow")
println("splitting looping over random text")
def datastream3:Stream[String] = DataOps.infiniteDataStream(n_lines)
BasicOps.dummyStringStreamSplit(datastream3)
println("RANDOM LINE SPLIT OK: no heap overflow")
}这是一个错误:
splitting looping over invariant text
INVARIANT LINE SPLIT OK: no heap overflow
splitting looping over random text
java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.String.valueOf(String.java:2840)
at java.lang.Character.toString(Character.java:2136)
at java.lang.String.valueOf(String.java:2826)
at scala.collection.mutable.StringBuilder.append(StringBuilder.scala:198)
at scala.collection.TraversableOnce$$anonfun$addString$1.apply(TraversableOnce.scala:350)
at scala.collection.immutable.List.foreach(List.scala:383)
at scala.collection.TraversableOnce$class.addString(TraversableOnce.scala:343)
at scala.collection.AbstractTraversable.addString(Traversable.scala:104)
at scala.collection.TraversableOnce$class.mkString(TraversableOnce.scala:309)
at scala.collection.AbstractTraversable.mkString(Traversable.scala:104)
at scala.collection.TraversableOnce$class.mkString(TraversableOnce.scala:311)
at scala.collection.AbstractTraversable.mkString(Traversable.scala:104)
at scala.collection.TraversableOnce$class.mkString(TraversableOnce.scala:313)
at scala.collection.AbstractTraversable.mkString(Traversable.scala:104)
at scala.util.Random.nextString(Random.scala:89)
at DataOps$$anonfun$randomText$1.apply(scalaOverflow.scala:5)
at DataOps$$anonfun$randomText$1.apply(scalaOverflow.scala:5)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.immutable.Range.foreach(Range.scala:160)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at DataOps$.randomText(scalaOverflow.scala:5)
at DataOps$.infiniteDataStream(scalaOverflow.scala:16)
at DataOps$$anonfun$infiniteDataStream$1.apply(scalaOverflow.scala:16)
at DataOps$$anonfun$infiniteDataStream$1.apply(scalaOverflow.scala:16)
at scala.collection.immutable.Stream$Cons.tail(Stream.scala:1117)
at scala.collection.immutable.Stream$Cons.tail(Stream.scala:1107)
at scala.collection.immutable.Stream$$anonfun$flatMap$1.apply(Stream.scala:458)
at scala.collection.immutable.Stream$$anonfun$flatMap$1.apply(Stream.scala:458)
at scala.collection.immutable.Stream.append(Stream.scala:241)
at scala.collection.immutable.Stream$$anonfun$append$1.apply(Stream.scala:241)更新
实际上,这种流的原因是基于下面的方法。关键是将java while循环转换为功能友好的Stream。
import java.sql.{Connection, ResultSet, Statement, DriverManager}
def sqlStream(psqlResult: ResultSet, colname:String): Stream[(Int,String)] = {
val state:Boolean = psqlResult.next()
if (state && psqlResult.getString(colname) != null)
(psqlResult.getRow(), psqlResult.getString(colname))#::sqlStream(psqlResult, colname)
else if (state)
sqlStream(psqlResult, colname)
else
Stream[(Int,String)]()
}我应该考虑一个更好的选择吗?
谢谢。
发布于 2014-06-18 13:07:50
datastream参数在dummyStringStreamSplit中的作用实际上就像一个val,并保持对传入流的开始的引用。这就是导致无界内存使用和最终GC开销限制超过错误的原因。
实际上,没有任何方法可以使用Stream并基于每个元素(而不仅仅是返回一个新的Stream)安全地计算某些内容。至少,无法保证客户端代码不会在某个变量中传递一个Stream。
如果您将dummyStringStreamSplit定义为:
def dummyStringStreamSplit(datastream: Stream[String]) =
datastream.flatMap(txt => txt.split(" "))然后你可以:
println("splitting looping over random text")
def datastream3:Stream[String] = DataOps.infiniteDataStream(n_lines)
def datastream3Split = BasicOps.dummyStringStreamSplit(datastream3)
datastream3Split.foreach(word => word)
println("RANDOM LINE SPLIT OK: no heap overflow")也不会得到GC开销超过错误的限制。
https://stackoverflow.com/questions/24282556
复制相似问题