[英]Why does primitive data type consume much memory than reference data type for this scenario in Java?
我試圖檢查程序的內存消耗。 在檢查過程中,我注意到了一些有趣的事情。
我創建了一個 Load 類,其中包含一些字段。
class Load {
String name;
String title;
long id;
}
我創建了 500000 個 Load 對象並將它們添加到 ArrayList。 我發現,它占用了大約18 MB
的內存。
然后,我修改了 Load 類並使用reference
類型 Long。
class Load {
String name;
String title;
Long id;
}
再次創建了 500000 個 Load 對象並將它們添加到 ArrayList。 有趣的是,這一次它占用的內存比前一次少。 它的方式是 14 MB。
運行測試更改操作系統和 JVM 版本。 找到以下結果。
OS: Windows 10 Pro 64 bit
JDK: 11 64bit
Object Created | Load Object | Memory | Load Object | Memory
------------------------------------------------------------------------------
1. 500000 | With primitive long | 18 MB | With reference Long | 14 MB
2. 900000 | | 32 MB | | 26 MB
3. 1500000 | | 53 MB | | 41 MB
OS: macOS Big Sur 64 bit
JDK: 8 64bit
Object Created | Load Object | Memory | Load Object | Memory
------------------------------------------------------------------------------
1. 500000 | With primitive long | 18 MB | With reference Long | 14 MB
2. 900000 | | 32 MB | | 26 MB
3. 1500000 | | 53 MB | | 41 MB
令人驚訝的是,在所有這些測試運行中,包含原始類型的 Object 比包含引用 Long 的 Object 消耗更多的內存。
內存測試代碼:
public class MemoryChecker {
private static final long MEGABYTE = 1024L * 1024L;
public static long bytesToMegabytes(long bytes) {
return bytes / MEGABYTE;
}
public static void main(String[] args) {
List<Load> list = new ArrayList<Load>();
for (int i = 0; i <= 500000
; i++) {
list.add(new Load("Jim", "Knopf", 11L));
}
// Get the Java runtime
Runtime runtime = Runtime.getRuntime();
// Run the garbage collector
runtime.gc();
// Calculate the used memory
long memory = runtime.totalMemory() - runtime.freeMemory();
System.out.println("Used memory is megabytes: " + bytesToMegabytes(memory));
}
}
完整代碼git repo 。
對於 32 位 JVM,以及具有CompressedOOPs功能(HotSpot JVM 支持並默認啟用)的 64 位 JVM,與long
的 8 個字節相比,引用僅消耗 4 個字節。
即使使用實際對象初始化引用,共享對象時也可能消耗較少的內存。 這適用於常量的自動裝箱:
如果被裝箱的值 p 是對
boolean
、byte
、char
、short
、int
或long
類型的常量表達式(第15.29 節)求boolean
的結果,並且結果為true
、false
,則為'\ '
范圍內的字符到'\'
,或-128
到127
范圍內的整數,然后讓a
和b
是p
的任何兩個裝箱轉換的結果。 總是a == b
的情況。
但也適用於所有以Long.valueOf(long)
結束的操作。
此方法將始終緩存 -128 到 127(含)范圍內的值,並且可能緩存此范圍之外的其他值。
當然,如果你創建了很多非共享的Long
對象,它們會比原始long
消耗更多的內存。 如果您使用許多不同的值,即使是潛在的共享它們也無濟於事。
由於“Long id”未初始化,因此它僅占用 4/8 字節(取決於 VM 和操作系統),其中“long id”默認使用 0L 初始化,占用 8 個字節。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.