问题 Scala - 在这种情况下,为什么Double比Floats消耗更少的内存?


这是我陷入的一种奇怪的行为,我找不到任何关于为什么会这样的暗示。我在这个例子中使用了 估计Spark的SizeEstimator方法 但是我没有在他们的代码中发现任何故障所以我想知道为什么 - 如果他们提供了很好的内存估计 - 为什么我有这个:

val buf1 = new ArrayBuffer[(Int,Double)]
var i = 0
while (i < 3) {
   buf1 += ((i,i.toDouble))
   i += 1
}
System.out.println(s"Raw size with doubles: ${SizeEstimator.estimate(buf1)}")
val ite1 = buf1.toIterator
var size1: Long = 0l
while (ite1.hasNext) {
   val cur = ite1.next()
   size1 += SizeEstimator.estimate(cur)
}
System.out.println(s"Size with doubles: $size1")

val buf2 = new ArrayBuffer[(Int,Float)]
i = 0
while (i < 3) {
   buf2 += ((i,i.toFloat))
   i += 1
}
System.out.println(s"Raw size with floats: ${SizeEstimator.estimate(buf2)}")
val ite2 = buf2.toIterator
var size2: Long = 0l
while (ite2.hasNext) {
   val cur = ite2.next()
   size2 += SizeEstimator.estimate(cur)
 }
 System.out.println(s"Size with floats: $size2")

控制台输出打印:

Raw size with doubles: 200
Size with doubles: 96
Raw size with floats: 272
Size with floats: 168

所以我的问题非常天真:为什么在这种情况下浮点数往往会占用更多的内存而不是双打?当我将它转换为迭代器时,为什么会变得更糟(第一种情况,当转换为迭代器时,有75%的比例变为50%!)。

(为了获得更多上下文,我在尝试通过更改来“优化”Spark应用程序时陷入了这种情况 Double 至 Float 并发现它实际上花了更多的内存浮动而不是双打...)

P.S。:这不是由于缓冲区的小尺寸(这里是3),如果我把100而不是我得到:

Raw size with doubles: 3752
Size with doubles: 3200
Raw size with floats: 6152
Size with floats: 5600

并且浮动仍然消耗更多的内存...但是比率已经稳定,所以似乎转换到迭代器的不同比率必然是由于我猜的一些开销。

编辑: 看起来 Product2 实际上只是专门的 IntLong 和 Double

trait Product2[@specialized(Int, Long, Double) +T1, @specialized(Int, Long, Double) +T2] extends Any with Product

有谁知道为什么 Float 没有考虑到?也不 Short 这会导致奇怪的行为......


10771
2018-02-24 09:23


起源

抱歉,在发布anwer之前我没有看到更新。如果您愿意,我可以删除答案 - Odomontois
没有你的答案是伟大的,因为你提供了一个链接,解释了为什么它不专注于所有原语!这是由于它会导致的组合数...这实际上是有道理的=)在尝试像我尝试的那样愚蠢地进行优化之前知道它是很好的! - Vince.Bdn


答案:


这是因为 Tuple2 是 @specialized 对于 Double 但不是专门的 Float

这意味着 (Int,Double) 将显示为具有2个原始java类型字段的结构 int 和 double,而 (Int,Float) 将作为结构呈现 int 和包装类型 java.lang.Float 领域

更多讨论 这里


13
2018-02-24 09:38



你的链接中有一些奇怪的东西,他们告诉它是因为他们不希望有太多的专业化。但是当你看代码时,Product3甚至不是专门的...所以它只是Product1和Prodcut2 ......他们可以很容易地在常规类型上添加一些专门用作浮动和短裤! - Vince.Bdn
@ Vince.Bdn Tuple2 经常使用的方式 Tuple3。所以我猜他们认为进一步的定义不值得库jar大小。您可以使用案例类进行有效的存储, miniboxing 有效访问和 无形的 用于有效的通用转换 - Odomontois