Java中的String到底佔用多大的記憶體空間?你所瞭解的可能都是錯誤的!!
寫在前面
最近小夥伴加群時,我總是問一個問題:Java中的String類佔用多大的記憶體空間?很多小夥伴的回答著實讓我哭笑不得,有說不佔空間的,有說1個位元組的,有說2個位元組的,有說3個位元組的,有說不知道的,更讓人哭笑不得的是竟然還有人說是2的31次方。那如果真是這樣的話,伺服器的記憶體空間還放不下一個字串呀!作為程式設計師的我們,可不能鬧這種笑話呀。今天,我們就一起來聊聊Java中的String到底佔用多大的記憶體空間!
Java物件的結構
首先,我們來下Java物件在虛擬機器中的結構,這裡,以HotSpot虛擬機器為例。
注:圖片來源http://r6d.cn/wp7q
從上面的這張圖裡面可以看出,物件在記憶體中的結構主要包含以下幾個部分:
- Mark Word(標記欄位):物件的Mark Word部分佔4個位元組,其內容是一系列的標記位,比如輕量級鎖的標記位,偏向鎖標記位等等。
- Klass Pointer(Class物件指標):Class物件指標的大小也是4個位元組,其指向的位置是物件對應的Class物件(其對應的後設資料物件)的記憶體地址
- 物件實際資料:這裡麵包括了物件的所有成員變數,其大小由各個成員變數的大小決定,比如:byte和boolean是1個位元組,short和char是2個位元組,int和float是4個位元組,long和double是8個位元組,reference是4個位元組
- 對齊:最後一部分是對齊填充的位元組,按8個位元組填充。
換種說法就是:
- 物件頭(object header):8 個位元組(儲存物件的 class 資訊、ID、在虛擬機器中的狀態)
- Java 原始型別資料:如 int, float, char 等型別的資料
- 引用(reference):4 個位元組
- 填充符(padding)
Java中的String型別
空String佔用的空間
這裡,我們以Java8為例進行說明。首先,我們來看看String類中的成員變數。
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
在 Java 裡陣列也是物件,因此陣列也有物件頭。所以,一個陣列所佔的空間為物件頭所佔的空間加上陣列長度加上陣列的引用,即 8 + 4 + 4= 16 位元組 。
所以,我們可以得出一個空String物件所佔用的記憶體空間,如下所示。
物件頭(8 位元組)+ 引用 (4 位元組 ) + char 陣列(16 位元組)+ 1個 int(4位元組)+ 1個long(8位元組)= 40 位元組
所以,小夥伴們,你們的回答正確嗎?
非空String佔用的空間
如果String字串的長度大於0的話,我們也可以得出String佔用記憶體的計算公式,如下所示。
40 + 2 * n
其中,n為字串的長度。
這裡,可能有小夥伴會問,為什麼是 40 + 2 * n 呢?這是因為40是空字串佔用的記憶體空間,這個我們上面已經說過了,String類實際上是把資料儲存到char[]這個成員變數陣列中的,而char[]陣列中的一個char型別的資料佔用2個位元組的空間,所以,只是String中的資料就會佔用 2 * n(n為字串的長度)個位元組的空間,再加上空字串所佔用的40個位元組空間,最終得出一個字串所佔用的儲存空間為: 40 + 2 * n (n為字串長度)。
注:40 + 2 * n 這個公式我們可以看成是計算String物件佔用多大記憶體空間的通用公式。
因此在程式碼中大量使用String物件時,應考慮記憶體的實際佔用情況。
驗證結論
接下來,我們就一起來驗證下我們上面的結論。首先,建立一個UUIDUtils類用來生成32位的UUID,如下所示。
package io.mykit.binghe.string.test;
import java.util.UUID;
/**
* @author binghe
* @version 1.0.0
* @description 生成沒有-的UUID
*/
public class UUIDUtils {
public static String getUUID(){
String uuid = UUID.randomUUID().toString();
return uuid.replace("-", "");
}
}
接下來,建立一個TestString類,在main()方法中建立一個長度為4000000的陣列,然後在陣列中放滿UUID字串,如下所示。
package io.mykit.binghe.string.test;
import java.util.UUID;
/**
* @author binghe
* @version 1.0.0
* @description 測試String佔用的記憶體空間
*/
public class TestString{
public static void main(String[] args){
String[] strContainer = new String[4000000];
for(int i = 0; i < 4000000; i++){
strContainer[i] = UUIDUtils.getUUID();
System.out.println(i);
}
//防止程式退出
while(true){
}
}
}
這裡,4000000個字串,每個字串的長度為32,所以儲存字串資料所佔用的記憶體空間為:(40 + 32 * 2) * 4000000 = 416000000位元組,約等於416MB。
我們使用Jprofiler記憶體分析工具進行分析:
可以看到,使用Jprofiler記憶體分析工具的結果為:321MB + 96632KB,約等於417MB。之所以使用Jprofiler記憶體分析工具得出的結果比我們計算的大些,是因為在程式實際執行的過程中,程式內部也會生成一些字串,這些字串也會佔用記憶體空間!!
所以,使用Jprofiler記憶體分析工具得出的結果符合我們的預期。
好了,今天就到這兒吧,希望小夥伴們能有所收穫,我是冰河,我們下期見!!
相關文章
- 一個Java物件到底佔用多大記憶體?Java物件記憶體
- VS上檢視某個類中各個成員變數所佔用的記憶體空間變數記憶體
- Java中的CPU佔用高和記憶體佔用高的問題排查Java記憶體
- 你瞭解Java記憶體模型麼(Java7、8、9記憶體模型的區別)Java記憶體模型
- 為什麼你的 64-bit 程式可能佔用巨大的虛擬空間
- 你可能不瞭解的java列舉Java
- python物件的記憶體佔用Python物件記憶體
- Java逐層解析JSON的記憶體佔用分析JavaJSON記憶體
- 記憶體拷貝引起的錯誤記憶體
- 你必須瞭解的java記憶體管理機制(四)-垃圾回收Java記憶體
- ArkTS 的記憶體空間詳解:從 SemiSpace 到 HugeObjectSpace記憶體Object
- Java中的記憶體模型詳解Java記憶體模型
- 記憶體插槽插滿就可以了?不,你的插法很可能是錯誤的記憶體
- 你和cdo之間的差距,到底有多大?
- Java虛擬機器的記憶體空間有幾種Java虛擬機記憶體
- Java虛擬機器的記憶體空間有幾種!Java虛擬機記憶體
- 高階面試必備:一個Java物件佔用多大記憶體面試Java物件記憶體
- 你真的瞭解Java記憶體模型JMM嗎?Java記憶體模型
- 如何檢視MySQL資料庫佔多大記憶體,佔用太多記憶體怎麼辦?MySql資料庫記憶體
- Redis的String型別,原來這麼佔記憶體Redis型別記憶體
- 開發板中的記憶體壓力測試,你瞭解多少?記憶體
- 關於Allowed memory size of (PHP記憶體溢位)錯誤的可能原因及解決方案PHP記憶體溢位
- mysql佔用記憶體高的一種解決方法MySql記憶體
- JVM元空間Metaspace的記憶體結構JVM記憶體
- Java應用程式中的記憶體洩漏及記憶體管理Java記憶體
- mac技巧|你可能不瞭解的實用操作~Mac
- 虛擬記憶體系統——瞭解記憶體的工作原理記憶體
- 5個常見的JavaScript記憶體錯誤JavaScript記憶體
- Java9後String的空間優化Java優化
- 13 張圖解 Java 中的記憶體模型圖解Java記憶體模型
- Redis 檢視所有 key 的 value 值所佔記憶體大小Redis記憶體
- Java String 物件,你瞭解多少?Java物件
- 如何使Xcode佔用更少的空間 Xcode佔用空間太大解決方法XCode
- Java 程式佔用 VIRT 虛擬記憶體超高的問題研究Java記憶體
- 檢視佔用磁碟空間的程式
- HANA資料庫查詢大表佔用記憶體空間 for hana 2.0資料庫記憶體
- Java的記憶體 -JVM 記憶體管理Java記憶體JVM
- SHARED POOL中KGH: NOACCESS佔用大量記憶體的問題分析記憶體