Java Scala不可变映射

Java Scala不可变映射,java,performance,scala,functional-programming,bigdata,Java,Performance,Scala,Functional Programming,Bigdata,我在创建地图时有一段代码,如: val map = gtfLineArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap 然后我使用此贴图创建我的对象: case class MyObject(val attribute1: String, val attribute2: Map[String:String]) 我正在阅读数百万行,并使用迭代器转换为MyObject。像 MyO

我在创建地图时有一段代码,如:

 val map = gtfLineArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap
然后我使用此贴图创建我的对象:

case class MyObject(val attribute1: String, val attribute2: Map[String:String]) 
我正在阅读数百万行,并使用迭代器转换为MyObject。像

MyObject("1", map)
当我这么做的时候,速度真的很慢,超过1小时,有2'000'000个条目

我从对象创建中删除贴图,但仍然执行拆分过程(第1节):

脚本在不到1分钟内运行的过程。对于200万条条目

我做了一些分析,看起来是在创建对象时,
val映射
到对象映射之间的赋值使过程变慢了。我错过了什么

更新以更好地解释问题:

如果您看到我的代码来解释我对2000000行的自迭代,将每行转换为一个内部对象,那么要迭代,我会:

it.map(cretateNewObject).toList
此迭代器遍历所有行,并使用函数
createNewObject
将它们转换为my对象

这实际上非常快,特别是使用dk14所说的大内存。性能问题在我的内部

`crateNewObject(val line:String)` 
此函数用于创建对象

`class MyObject(val attribute1:String, val attribute2:Map[String, String])` 
my函数首先执行这一行

`val attributeArr = line.split("\t")` 
数组的第一个属性记录是my object的attribute1,第二个属性是

`val map = attributeArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap` 
如果我只打印map中的元素数量,程序将在2分钟内结束,如果我将map传递给我的新对象行
MyObject(attribute1,map)
程序非常慢。

(0到2000000)。toList
(0到2000000)。map(x=>x->x)。如果给它们足够的内存,toMap
也有类似的性能(我尝试了-Xmx4G-4G字节)。
toMap的实现很大程度上与克隆有关,因此大量内存被“分配”/“解除分配”。因此,在内存不足的情况下,GC变得过于活跃

当我试图用128Mb运行
(0到2000000)。toList
(0到2000000)。这需要几秒钟的时间,但是
(0到2000000)。map(x=>x->x)。toMap
在10%GC活动(VisualVM)的情况下至少需要2分钟,并因内存不足而死亡

然而,当我尝试
-Xmx4G
时,两者都非常快


另外,
toMap
所做的是重复地将一个元素添加到前缀树中,因此它必须对每个元素进行大量克隆(
Array.copy

因此,
toMap
重复(2000000次)执行
updated0
,这反过来又执行一个
数组。复制
非常频繁,这需要大量内存分配,这(在内存不足的情况下)会导致GC在大部分时间(从jconsole中可以看到)执行标记和扫描(缓慢的垃圾收集)



解决方案:无论是增加内存(
-Xmx
/
-Xms
JVM参数),还是需要对数据集执行更复杂的操作,都可以使用apachespark(或任何面向批处理的map-reduce框架)以分布式方式处理数据。

在第二种情况下,您可能不会在任何地方使用
val-map
,因此编译器只是将该行中的代码扔掉,而不会拆分任何内容。Hi@kolman不是这种情况,因为
gtfLineArr(8).split(;”).map(split“\”).collect{case-Array(k,v)=>(k,v)}.toMap
计算分割并将结果转换为一个映射。实际上,我做了
gtfLineArr(8).split(“;”).Map(\usplit“\”)。收集{case Array(k,v)=>(k,v)}.toMap.size
并打印结果,这一分钟意味着映射被创建。我怀疑的是,当映射被传递到新对象时,正在做“一些”造成问题的转换。您的代码还做了什么?这些行中可能没有花费时间。Dima不是真的。正如我所说。当我通过null删除映射到构造函数的赋值时。那么程序真的很快。只需尝试
(0到2000000)。toList
vs
(0到2000000)。map(x=>x->x).toMap
以获得纯结果我知道
.toMap
非常耗时。但是,如果您看到示例,该操作仅对每个条目执行,而不是对列表进行计数。我一直在进行一些分析,似乎每次都收集为
映射[String,String]
,并且映射被传递给对象(对于200万个条目中的每个条目)从char[]进行一些转换执行to String。正如我在示例中所说,我尝试运行的实际代码如下:@ypriverol不是
。toMap
很耗时,是因为映射使用了大量内存。如果保留
MyObject
的实例,那么第一个被剪切的实例需要比第二个实例更多的内存才能运行。
`val map = attributeArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap`