一個java物件到底佔多大記憶體?
最近在讀《深入理解Java虛擬機》,對Java物件的記憶體佈局有了進一步的認識,於是腦中自然而然就有一個很普通的問題,就是一個Java物件到底佔用多大記憶體?
在網上搜到了一篇博客講的非常好:http://yueyemaitian.iteye.com/blog/2033046,裡面提供的這個類別也非常實用:
import java.lang.instrument.Instrumentation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; import java.util.Set; /** * 对象占用字节大小工具类 * * @author tianmai.fh * @date 2014-03-18 11:29 */ public class SizeOfObject { static Instrumentation inst; public static void premain(String args, Instrumentation instP) { inst = instP; } /** * 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、<br></br> * 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;<br></br> * 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小 <br></br> * * @param obj * @return */ public static long sizeOf(Object obj) { return inst.getObjectSize(obj); } /** * 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小 * * @param objP * @return * @throws IllegalAccessException */ public static long fullSizeOf(Object objP) throws IllegalAccessException { Set<Object> visited = new HashSet<Object>(); Deque<Object> toBeQueue = new ArrayDeque<Object>(); toBeQueue.add(objP); long size = 0L; while (toBeQueue.size() > 0) { Object obj = toBeQueue.poll(); //sizeOf的时候已经计基本类型和引用的长度,包括数组 size += skipObject(visited, obj) ? 0L : sizeOf(obj); Class<?> tmpObjClass = obj.getClass(); if (tmpObjClass.isArray()) { //[I , [F 基本类型名字长度是2 if (tmpObjClass.getName().length() > 2) { for (int i = 0, len = Array.getLength(obj); i < len; i++) { Object tmp = Array.get(obj, i); if (tmp != null) { //非基本类型需要深度遍历其对象 toBeQueue.add(Array.get(obj, i)); } } } } else { while (tmpObjClass != null) { Field[] fields = tmpObjClass.getDeclaredFields(); for (Field field : fields) { if (Modifier.isStatic(field.getModifiers()) //静态不计 || field.getType().isPrimitive()) { //基本类型不重复计 continue; } field.setAccessible(true); Object fieldValue = field.get(obj); if (fieldValue == null) { continue; } toBeQueue.add(fieldValue); } tmpObjClass = tmpObjClass.getSuperclass(); } } } return size; } /** * String.intern的对象不计;计算过的不计,也避免死循环 * * @param visited * @param obj * @return */ static boolean skipObject(Set<Object> visited, Object obj) { if (obj instanceof String && obj == ((String) obj).intern()) { return true; } return visited.contains(obj); } }
可以用這個代碼邊看邊驗證,注意的是,執行這個程式需要透過javaagent注入Instrumentation,具體可以看原始部落格。我今天主要是總結下手動計算Java物件佔用位元組數的基本規則,做為基本的技能必須get√,希望能幫助到跟我一樣的Java菜鳥。
在介紹之前,簡單回顧下,Java物件的記憶體佈局:物件頭(Header),實例資料(Instance Data)和對齊填充(Padding),詳細的可以看我的閱讀筆記。另外:不同的環境結果可能有差異,我所在的環境是HotSpot虛擬機,64位Windwos。
下面進入正文:
物件頭
物件頭在32位元系統上佔用8bytes,64位元系統上佔用16bytes。
實例資料
原生類型(primitive type)的記憶體佔用如下:
itive 類型 Memory Required(bytes) 1
short 2
char 2
int 4
float 4
long 8
double 8
tes, referenceence在32位元系統上佔用每個位元系統所佔用每個位元系統類型。 對齊填充 HotSpot的對齊方式為8位元組對齊:(物件頭+ 實例資料+ padding) % 8等於0且0 <= padding < 8『到VM參數UseCompressedOops的影響。
1)對物件頭的影響
開啟(-XX:+UseCompressedOops)物件頭大小為12bytes(64位元機器)。
static class A { int a; }
A物件佔用記憶體狀況:
關閉指標壓縮: 16+4=20不是8的倍數,所以+padding/4=24
1
11 開啟指標已經是8的倍數了,不需要再padding。 2) 對reference類型的影響
static class B2 { int b2a; Integer b2b; }
B2物件佔用記憶體狀況:
關閉指標壓縮: 16+4+8=28不是8的倍數,所以+padding/4=32 開啟指標
1 =20不是8的倍數,所以+padding/4=24
數組物件64位元機器上,陣列物件的物件頭佔用24個位元組,啟用壓縮之後佔用16個位元組。之所以比一般物件佔用記憶體多是因為需要額外的空間儲存數組的長度。
先考慮下new Integer[0]佔用的記憶體大小,長度為0,也就是物件頭的大小: 未開啟壓縮:24bytes1
接著計算new Integer[1],new Integer[2],new Integer[3]和new Integer[4]就很容易了:
未開啟壓縮:
开启压缩:
拿new Integer[3]来具体解释下:
未开启压缩:24(对象头)+8*3=48,不需要padding;
开启压缩:16(对象头)+3*4=28,+padding/4=32,其他依次类推。
自定义类的数组也是一样的,比如:
static class B3 { int a; Integer b; }
new B3[3]占用的内存大小:
未开启压缩:48
开启压缩后:32
复合对象
计算复合对象占用内存的大小其实就是运用上面几条规则,只是麻烦点。
1)对象本身的大小
直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小; 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小。
static class B { int a; int b; } static class C { int ba; B[] as = new B[3]; C() { for (int i = 0; i < as.length; i++) { as[i] = new B(); } } }
未开启压缩:16(对象头)+4(ba)+8(as引用的大小)+padding/4=32
开启压缩:12+4+4+padding/4=24
2)当前对象占用的空间总大小
递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小。
递归计算复合对象占用的内存的时候需要注意的是:对齐填充是以每个对象为单位进行的,看下面这个图就很容易明白。
现在我们来手动计算下C对象占用的全部内存是多少,主要是三部分构成:C对象本身的大小+数组对象的大小+B对象的大小。
未开启压缩:
(16 + 4 + 8+4(padding)) + (24+ 8*3) +(16+8)*3 = 152bytes
开启压缩:
(12 + 4 + 4 +4(padding)) + (16 + 4*3 +4(数组对象padding)) + (12+8+4(B对象padding))*3= 128bytes
大家有兴趣的可以试试。
实际工作中真正需要手动计算对象大小的场景应该很少,但是个人觉得做为基础知识每个Java开发人员都应该了解,另外:对自己写的代码大概占用多少内存,内存中是怎么布局的应该有一个直觉性的认识。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。
