4
我有一個包裝類,可以存儲一個Long,Double或Boolean原始值(以及爲簡單起見我已刪除的其他一些東西)。我最初的樸素實現只是將包裝後的值存儲在Any類型的字段中,導致值被裝箱。如何將Scala @specialized用於基元周圍的內存有效包裝類?
要刪除拳擊和減少內存使用情況,我嘗試使用泛型,但得知由於類型擦除,這不會保存任何內容。所以我嘗試使用@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字節?
案例類不適用於您的示例嗎? – Appleshell 2013-05-03 18:05:25
@AdamS - 當然,但'case'比'val'長,否則對示例沒有任何幫助:) – 2013-05-03 18:14:20
我只是好奇,因爲我從來沒有發現case case類的用法;(相對較新的對斯卡拉) – Appleshell 2013-05-03 18:17:04