gpt4 book ai didi

scala - 如何将 Scala @specialized 用于围绕基元的内存高效包装类?

转载 作者:行者123 更新时间:2023-12-04 18:10:03 26 4
gpt4 key购买 nike

我有一个包装类,可以存储 Long、Double 或 Boolean 原始值(以及为简单起见我已删除的其他一些内容)。我最初的天真实现只是将包装的值存储在 Any 类型的字段中,这导致值被装箱。

为了消除装箱并减少内存使用,我尝试使用泛型,但了解到由于类型删除,这不会保存任何内容。所以我尝试使用@specialized,但得到了令人惊讶的结果。

以下代码使用 scalac 2.9.3 构建并在 JDK7 上运行。 MemoryMeasurer 来自 here我相信它是准确的。 “填充”字段不重要;我只是用它来填充基础对象(没有包装的值)到 16 个字节,所以我的各种尝试的效果更加清晰。

import objectexplorer.MemoryMeasurer

class GenericNonSpecialized[A] (wrapped: A, val padding: Int) {
def getWrapped: Any = wrapped
}

class GenericSpecialized[@specialized(Long, Double, Boolean) A] (wrapped: A, val padding: Int) {
def getWrapped: A = wrapped
}

class GenericSpecializedVal[@specialized(Long, Double, Boolean) A] (val wrapped: A, val padding: Int) {
def getWrapped: A = wrapped
}

class NonGeneric(val wrapped: Long, padding: Int) {
}

object App {
def main(args: Array[String]) {
println(MemoryMeasurer.measureBytes(new GenericNonSpecialized(4L, 0)))
// Expect: 48: NonSpecialized object (24 bytes) + boxed long (24 bytes)
// Actual: 48

// I expect all of the below to be 24 bytes: Object overhead (12 bytes) + Long (8 bytes) + Int (4 bytes),
// but only the non-generic one is actually 24 bytes.

println(MemoryMeasurer.measureBytes(new GenericSpecialized(4L, 0))) // 56

println(MemoryMeasurer.measureBytes(new GenericSpecializedVal(4L, 0))) // 32

println(MemoryMeasurer.measureBytes(new NonGeneric(4L, 0))) // 24
}
}

问题:
  • 我如何创建一个使用 24 字节的通用包装器对象,就像非通用的等价物? (我的最佳尝试,GenericSpecializedVal 使用 32)
  • 为什么 GenericNonSpecialized 使用 56 个字节,但如果我添加“val”,使“包装”到实际字段中,它会下降到 32 个字节?
  • 最佳答案

    不幸的是,专用类继承自它们的非专用父类,并且该父类包含用于盒装副本的存储空间。因此,简短的回答是您无法以这种方式形成有效的包装器。

    您可以在特征中声明数据:

    trait Boxer[@specialized A]{ def boxed: A }

    然后手动提供实现:
    class BoxerInt(val boxed: Int) extends Boxer[Int]
    class BoxerDouble(val boxed: Double) extends Boxer[Double]

    然后编写 Boxer 伴侣来重载 apply 方法:
    object Boxer {
    def apply(i: Int) = new BoxerInt(i)
    def apply(d: Double) = new BoxerDouble(d)
    }

    这样你就可以让它看起来好像你不必做所有的工作:
    val box = Boxer(5.0)

    但它仍然不能与特化的其他用途完全无缝(特别是在通用上下文中创建始终是一个问题)。

    关于scala - 如何将 Scala @specialized 用于围绕基元的内存高效包装类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16364795/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com