- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我想在scala中比较不可变的.map和可变的.map的性能特征,以便进行类似的操作(即将多个映射合并为一个映射)。请参见)。对于可变映射和不可变映射,我有类似的实现(见下文)。
作为一个测试,我生成了一个包含1000000个单项映射[int,int]的列表,并将这个列表传递到我测试的函数中。有了足够的内存,结果就不足为奇了:对于mutable.map,大约1200毫秒;对于unmutable.map,大约1800毫秒;对于使用mutable.map的命令式实现,大约750毫秒;map——不确定是什么造成了巨大的差异,但也可以对此发表评论。
让我有点吃惊的是,也许因为我有点厚,在Intellij8.1中使用默认的运行配置时,两个可变的实现都遇到了内存不足错误,但不可变的集合没有。不变的测试确实运行到了完成,但它运行得非常缓慢——大约需要28秒。当我增加了最大的JVM内存(大约200MB,不确定阈值在哪里)时,我得到了上面的结果。
不管怎样,我想知道的是:
为什么可变实现耗尽了内存,而不可变实现却没有呢?我怀疑不可变版本允许垃圾收集器在可变实现之前运行并释放内存——所有这些垃圾收集都解释了不可变低内存运行的缓慢性——但我希望得到更详细的解释。
实现如下。(注意:我不认为这些是可能的最佳实现。请随时提出改进建议。)
def mergeMaps[A,B](func: (B,B) => B)(listOfMaps: List[Map[A,B]]): Map[A,B] =
(Map[A,B]() /: (for (m <- listOfMaps; kv <-m) yield kv)) { (acc, kv) =>
acc + (if (acc.contains(kv._1)) kv._1 -> func(acc(kv._1), kv._2) else kv)
}
def mergeMutableMaps[A,B](func: (B,B) => B)(listOfMaps: List[mutable.Map[A,B]]): mutable.Map[A,B] =
(mutable.Map[A,B]() /: (for (m <- listOfMaps; kv <- m) yield kv)) { (acc, kv) =>
acc + (if (acc.contains(kv._1)) kv._1 -> func(acc(kv._1), kv._2) else kv)
}
def mergeMutableImperative[A,B](func: (B,B) => B)(listOfMaps: List[mutable.Map[A,B]]): mutable.Map[A,B] = {
val toReturn = mutable.Map[A,B]()
for (m <- listOfMaps; kv <- m) {
if (toReturn contains kv._1) {
toReturn(kv._1) = func(toReturn(kv._1), kv._2)
} else {
toReturn(kv._1) = kv._2
}
}
toReturn
}
最佳答案
嗯,这真的取决于你使用的地图的实际类型。可能HashMap
。现在,这种可变结构通过预先分配预期使用的内存来获得性能。你要加入一百万张地图,所以最终的地图一定会有点大。让我们看看如何添加这些键/值:
protected def addEntry(e: Entry) {
val h = index(elemHashCode(e.key))
e.next = table(h).asInstanceOf[Entry]
table(h) = e
tableSize = tableSize + 1
if (tableSize > threshold)
resize(2 * table.length)
}
2 *
行中的
resize
可变的
HashMap
每次耗尽空间时都会增加一倍,而不可变的则在内存使用上相当保守(尽管现有的键在更新时通常会占用两倍的空间)。
Tuple2
(key/value pairs)!加上
List
的开销,这是很小的,但是我们讨论的是超过一百万个元素乘以开销。
Stream
,这对于我们的目的来说不是很可靠。但是,请尝试以下方法:
for (m <- listOfMaps.projection; kv <- m) yield kv
Stream
不会计算该值。垃圾收集器也应该收集未使用的元素,只要您不保留对
Stream
头的引用,这在您的算法中似乎是如此。
l2
中。创建新列表的不是
val l2 =
,而是用于理解的。
val l = List(1,2,3)
val l2 = for (e <- l) yield e*2
mutable
关键字):
(Map[A,B]() /: (for (m <- listOfMaps; kv <-m) yield kv))
foldLeft
运算符将在返回的对象上调用,以便理解。记住,操作符末尾的
/:
会颠倒对象和参数的顺序。
:
。其中第一个用于理解的生成器是
foldLeft
。我们知道,
m <- listOfMaps
是类型列表[x]的集合,其中x在这里并不真正相关。对一个理解的结果总是另一个理解的结果。其他发电机不相关。
listOfMaps
中的所有键/值,它是这个
List
的一个组成部分,然后用所有这些创建一个新的
List
。这就是为什么你要复制你所有的东西。
List
有何帮助。
Map
上调用
List
时,它将返回类型为
List
的新对象(在scala 2.7.x上)。起初,您可能认为这只会使事情变得更糟,因为现在您将拥有三份
listOfMaps
而不是一份。但a
projection
不是预先计算的。它是懒散计算的。
projection
不是
List
的副本,而是一个可以在需要时用来计算
Stream
的函数。计算后,结果将保留,这样就不需要再次计算。
List
、
Stream
和
Stream
of a
List
all返回一个新的
Stream
,这意味着您可以将它们链接在一起,而无需制作创建它们的
map
的单个副本。因为对于理解
flatMap
使用这些功能,所以在内部使用
filter
可以防止不必要的数据复制。
val kvs = for (m <- listOfMaps.projection; kv <-m) yield kv
(Map[A,B]() /: kvs) { ... }
Stream
分配给
Stream
后,数据尚未被复制。不过,一旦执行了第二行,KVS将计算出它的每个元素,因此,它将保存数据的完整副本。
(Map[A,B]() /: (for (m <- listOfMaps.projection; kv <-m) yield kv))
List
的同时使用它。让我们简单地看看如何定义
yield
for a
Stream
override final def foldLeft[B](z: B)(f: (B, A) => B): B = {
if (isEmpty) z
else tail.foldLeft(f(z, head))(f)
}
Stream
为空,只需返回蓄能器。否则,计算一个新的累加器(
kvs
),然后将它和函数传递给
Stream
的
foldLeft
。
Stream
之后,就不会有任何对
Stream
的引用了。或者,换句话说,程序中的任何地方都不会指向
f(z, head)
的
tail
,这意味着垃圾收集器可以收集它,从而释放内存。
Stream
,因此没有任何数据的副本。在这种情况下,使用
f(z, head)
只会添加一个间接层。
关于performance - Scala:可变对象与不可变对象(immutable对象)性能 - OutOfMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1308682/
我正在尝试将用户提供的经纬度值与数据库中的经纬度值进行比较。如果它们在彼此半径 15 公里内,则应更改 TextView 。但我面临以下错误, 我的数据库包含值 source lat = 19.218
我在我的应用程序中使用改造来下载一些媒体文件,如视频、mp3、jpg、pdf 等。当我想下载一个 55MB 的 mp4 格式的大文件时,这是一个问题。当我想下载这个文件时,我收到这样的错误: OutO
所以我正在创建一个 Android 应用程序,这段代码引发了 "Caused by: java.lang.OutOfMemoryError: OutOfMemoryError thrown while
直到昨天,我的应用程序运行良好,但我所做的是,由于某些原因,我不得不在 Android Studio 中打开具有不同工作空间的同一个应用程序。从那时起,当我尝试运行该应用程序时,我遇到了以下异常,所以
我正在尝试构建一个应用程序,其中客户端将其屏幕发送到服务器,客户端仅在上次发送屏幕和最新捕获的屏幕之间存在差异时才发送其屏幕(以便该程序在网络)。服务器使用 JFrame 和 JLabel 来显示图像
我正在尝试使用内存映射模式在 cupy 中加载一些较大的 .npy 文件,但我不断遇到 OutOfMemoryError 。 我认为,由于它是在内存映射模式下打开的,因此此操作不应该占用太多内存,因为
我正在尝试对基于 ant 的(Netbeans RCP)项目进行分级并找到奇怪的分级行为。 我用探查器做了一些观察,得到了下一个结果。 环境配置 Gradle 1.9 Build time: 20
我有一个应用程序可以进行网络调用并检索 XML 数据。如果没有太多数据,下面的代码可以正常工作。 public class WebClient { private static final S
在我的应用程序中,我每 3 分钟刷新一次数据。如果应用程序可以工作几个小时,我会遇到这样的错误: java.lang.OutOfMemoryError at org.apache.http.util.
我在我的一个应用程序中偶尔收到 OutOfMemoryError: (Heap Size=49187KB, Allocated=41957KB)。我该怎么做才能诊断? 01-09 10:32:02
对于学校项目,我必须编写不同类型的算法。问题是,我得到了一个工作算法。但是我必须多次运行它,一段时间后它给了我以下错误: Exception in thread "main" java.lang.Ou
这个问题在这里已经有了答案: 8年前关闭。 Possible Duplicate: Recursive function causing a stack overflow 完成示例惰性序列 here
我收到 java.lang.OutOfMemoryError 错误,即使我还有足够的空闲 RAM。我进行的内存转储在 200MB 到 1GB 之间,而我的服务器有 24GB 的 RAM。我设置了 -X
我不明白为什么这段代码没有OutOfMemoryError public static void main(String[] args) { Object[] ref = new Object
我正在使用这个语句 //some code int a[][]=new int[5000000][5000000]; //some code 并使用命令运行它 java -mx512m Test 它给
今天我在玩OOM错误,我发现了一些我自己无法解释的东西。 我尝试分配一个比堆大的数组,期望 “请求的阵列大小超出 VM 限制”错误,但我得到一个“ Java 堆空间 ”错误。 根据JDK 11 doc
我有一个显示图像的简单页面。来源是 URL var img = new Image (); var source = new UriImageSource { Uri =
我有一个 Java Spring Boot 应用程序。它是一个非常大的应用程序,具有许多服务,并且可以执行大量任务。我尝试实现的新任务之一是从 Oracle DB 读取一些数据并通过 REST 将其发
我正在尝试使用流读取一个非常大的文件,因此我需要并行流而不是每行迭代...我正在尝试如下: String cont = new String(Files.readAllBytes(Paths.get(
假设我们的最大内存为 256M,为什么这段代码可以工作: public static void main(String... args) { for (int i = 0; i < 2; i++)
我是一名优秀的程序员,十分优秀!