2012-01-27 35 views
10

在Java中,以字節爲單位的大小是一個盒裝基元,如java.lang.Integerjava.lang.CharacterJava中盒裝原語的存儲成本是多少?

一種int是4個字節,一個典型的指針也4字節(如果不是由JVM壓縮)。是整數(沒有緩存)的成本,因此4 bytes + 4 bytes = 8 bytes?在對象中是否還有更多隱藏的字段或額外的開銷(即,對於我不知道的對象而言,是否存在一般成本?)。

我對緩存問題不感興趣。我知道一定範圍內的整數由JVM緩存。

人們可以改寫的問題:什麼是對的內存用於盒裝值與原始值量相乘的最大因素是什麼?

編輯:我明白,JVM的多個實現存在。典型的32位HotSpot實現的典型成本是多少?

+7

從某個角度來看,這個問題是無法回答的,因爲在任何規範中沒有指定盒裝原語的開銷。它可以並且會因虛擬機和平臺而不同。具有標記內存的硬件平臺甚至可以具有零開銷。 – 2012-01-27 17:37:43

+0

[在Java中,什麼是確定對象大小的最佳方法?](http://stackoverflow.com/questions/52353/in-java-what-is-the-best-way-to-確定最尺寸的-一個對象)。 – DwB 2012-01-27 17:52:03

+0

我認爲它也可能取決於您使用盒裝int的上下文以及運行時編譯器正在進行的任何優化。 – 2012-01-27 17:54:03

回答

5

這是實現定義的,所以沒有具體的答案。但我應該能夠爲Hotspot回答它。

你需要知道的是:熱點總是將上8字節邊界的對象。此外,每個對象都有2個字開銷。 [1]

如果我們把這個我們一起得到:

32位VM:4字節整數+ 2個字對象標題= 12bytes。這不是8的倍數,因此1整數的成本是8的下一個倍數:16字節。

64位VM:4字節整數+ 2字= 20字節。再次向上舍入:24字節大小。

基準的大小顯然不發揮到對象本身的大小,除非它具有不是一個簡單的INT包裝的情況下對其他對象的引用。如果可以的話,對於64位JVM,現在的JVM(否則爲8字節),我們將32位和4字節的堆棧分別爲4byte,< = 32GB,CompressedOops

[1]有興趣的人可以看看代碼share/vm/oops/oop.hpp

+1

爲了完整起見:如果對象是同步的,將會有一個本地struct持有互斥鎖。 – bestsss 2012-01-30 15:16:05

+0

@bestsss對,完全忽略了。我認爲僅當我們有一個競爭鎖時纔會創建重量級鎖(假設偏向鎖定)。如果我們不這樣做,並且不使用對象的散列碼,我認爲Hotspot將tid存儲在對象頭本身中。所以只調用'synchronized(foo)'可能不一定分配任何內存。 – Voo 2012-01-30 16:03:00

+0

是的。如果存在System.identityHashCode()請求,無約束偏見的鎖不會膨脹標題。後者用於(非官方)防止對選定對象進行偏置鎖定。 (我的意思主要是滿足 - >有時我用'對象鎖=新的字節(1)'來簡化序列化 – bestsss 2012-01-30 16:54:52

1

不止這些。

每個對象引用都有額外開銷,例如Class引用。不僅如此,你的4字節指針不太準確。它是一個引用,所以它是一個ID加上一個指針,並且如果您位於64位JVM上,該指針可能爲8個字節。

似乎還存在VM實施差異。確保這一點的最佳方法是將其放在探查器中。

我的(超級SWAG)估計會。 對象引用的16個字節(64位JVM) 類參考16個字節 原始值的4個字節(假設中間體) 總計。 36個字節。

編輯:現在你指定的32位JVM我的贓物將使用上述相同的數學20個字節。

+0

我沒有絲毫的想法,你是怎麼想出這些數字的......在'oop.hpp'中查看我的Hotspot源代碼也使得我不明智(我只能找到通常的2指針) – Voo 2012-01-27 17:56:53

0

我知道這並不完全回答你的問題上盒裝元的存儲成本,但我從你的問題感覺到你在質疑是否不是你使用它們是有保證的。

這裏是由Joshua布洛赫從有效的Java(第2版)的摘錄,應該幫助你決定:

"So when should you use boxed primitives? They have several legitimate uses. The first is as elements, keys, and values in collections. You can’t put primitives in collections, so you’re forced to use boxed primitives. This is a special case of a more general one. You must use boxed primitives as type parameters in parame- terized types (Chapter 5), because the language does not permit you to use primi- tives. For example, you cannot declare a variable to be of type Thread- Local<int>, so you must use ThreadLocal<Integer> instead. Finally, you must use boxed primitives when making reflective method invocations (Item 53).

In summary, use primitives in preference to boxed primitives whenever you have the choice. Primitive types are simpler and faster. If you must use boxed primitives, be careful! Autoboxing reduces the verbosity, but not the danger, of using boxed primitives. When your program compares two boxed primitives with the == operator, it does an identity comparison, which is almost certainly not what you want. When your program does mixed-type computations involving boxed and unboxed primitives, it does unboxing, and when your program does unboxing, it can throw a NullPointerException. Finally, when your program boxes primitive values, it can result in costly and unnecessary object creations."

希望有所幫助。