java統計空間占用_JVM —— Java 對象占用空間大小計算

引用類型(reference type: Integer)在 32 位系統上每一個占用 4bytes(即32bit, 才干管理 2^32=4G 的內存), 在 64 位系統上每一個占用 8bytes(開啟壓縮為 4 bytes)。

四. 對齊填充

HotSpot 的對齊方式為 8 字節對齊。不足的須要 Padding 填充對齊, 公式:(對象頭 + 實例數據 + padding)% 8 == 0 (0<= padding <8)

五. 計算 Java 對象占用空間大小

借助 Instrument 接口的 getObjectSize 方法計算對象占用空間

SizeOfAgent: 計算對象大小類

package com.wenniuwuren.objectsizeof;

import java.lang.instrument.Instrumentation;

import java.lang.reflect.Array;

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

import java.util.IdentityHashMap;

import java.util.Map;

import java.util.Stack;

/**

* 借助 Instrumentation 接口的 getObjectSize 方法計算對象占用空間

* 原來的 sizeOf 僅僅能計算本對象占用空間, 無法計算繼承下來的占用空間,

* 只是能夠用反射的方法把全部占用空間計算出來

*

* Created by zhuyb on 16/3/20.

*/

public class SizeOfAgent {

static Instrumentation instrumentation;

// 第一個參數由 –javaagent。 第二個參數由 JVM 傳入

public static void premain(String agentArgs, Instrumentation instP) {

instrumentation = instP;

}

// 返回沒有子類對象大小的大小

public static long sizeOf(Object o) {

if (instrumentation == null) {

throw new IllegalStateException("Can not access instrumentation environment.\n" +

"Please check if jar file containing SizeOfAgent class is \n" +

"specified in the java's \"-javaagent\" command line argument.");

}

return instrumentation.getObjectSize(o);

}

/**

*

* 計算復合對象

* @param obj object to calculate size of

* @return object size

*/

public static long fullSizeOf(Object obj) {

Map visited = new IdentityHashMap();

Stack stack = new Stack();

long result = internalSizeOf(obj, stack, visited);

while (!stack.isEmpty()) {

result += internalSizeOf(stack.pop(), stack, visited);

}

visited.clear();

return result;

}

// 這個算法使每一個對象僅被計算一次。 避免循環引用,即死循環計算

private static boolean skipObject(Object obj, Map visited) {

if (obj instanceof String) {

// String 池里已有的不再計算

if (obj == ((String) obj).intern()) {

return true;

}

}

return (obj == null) // 已有對象不再計算

|| visited.containsKey(obj);

}

private static long internalSizeOf(Object obj, Stack stack, Map visited) {

if (skipObject(obj, visited)){

return 0;

}

visited.put(obj, null);

long result = 0;

// get size of object + primitive variables + member pointers

result += SizeOfAgent.sizeOf(obj);

// 處理全部數組內容

Class clazz = obj.getClass();

if (clazz.isArray()) {

// [I , [F 基本類型名字長度是2

if(clazz.getName().length() != 2) {// skip primitive type array

int length = Array.getLength(obj);

for (int i = 0; i < length; i++) {

stack.add(Array.get(obj, i));

}

}

return result;

}

// 處理對象的全部字段

while (clazz != null) {

Field[] fields = clazz.getDeclaredFields();

for (int i = 0; i < fields.length; i++) {

// 不反復計算靜態類型字段

if (!Modifier.isStatic(fields[i].getModifiers())) {

// 不反復計算原始類型字段

if (fields[i].getType().isPrimitive()) {

continue;

} else {

// 使 private 屬性可訪問

fields[i].setAccessible(true);

try {

// objects to be estimated are put to stack

Object objectToAdd = fields[i].get(obj);

if (objectToAdd != null) {

stack.add(objectToAdd);

}

} catch (IllegalAccessException ex) {

assert false;

}

}

}

}

clazz = clazz.getSuperclass();

}

return result;

}

}

使用上述代碼必須將上述代碼打成 jar 包, 而且 MANIFEST.MF 文件設置參數(

Premain-Class:sizeof.agent.SizeOfAgent

Boot-Class-Path:

Can-Redefine-Classes:false

)

假設使用 Maven 打包的話, 能夠直接在 pom.xml 里面設置 MANIFEST.MF 的參數 :

maven-jar-plugin

2.4

SizeOfAgent

com.wenniuwuren.objectsizeof.SizeOfAgent

false

false

測試類: SizeOfAgentTest

package com.wenniuwuren.objectsizeof;

import static com.wenniuwuren.objectsizeof.SizeOfAgent.*;

/**

* 下面結果在 64-bit JVM 下測試

* 啟動參數1(不壓縮指針長度):-javaagent:target/SizeOfAgent.jar -XX:-UseCompressedOops

*

* Created by zhuyb on 16/3/20.

*/

public class SizeOfAgentTest {

public static void main(String[] args) {

System.out.println("------------------空對象----------------------------");

// 16 bytes + 0 + 0 = 16 空對象, 僅僅有對象頭

System.out.println("sizeOf(new Object()) = " + sizeOf(new Object()));

System.out.println("fullSizeOf(new Object()) = " + fullSizeOf(new Object()));

System.out.println("----------------非空對象含有原始類型、引用類型------------------------------");

// 16 bytes + 8 + 4 + padding = 32

System.out.println("sizeOf(new A()) = " + sizeOf(new A()));

System.out.println("fullSizeOf(new A()) = " + fullSizeOf(new A()));

// 16 + 4 + padding =24 數據是一個 int

System.out.println("sizeOf(new Integer(1)) = " + sizeOf(new Integer(1)));

// (16 + int hash:4 + int hash32:4 + refer char value[]:8 + padding) = 32

// 靜態屬性(static)不計算空間。由于全部對象都是共享一塊空間的

// 不同版本號JDK可能 String 內部 Field 可能不同,本次測試使用JDK1.7

System.out.println("sizeOf(new String()) = " + sizeOf(new String()));

// (16 + 4 + 4 + 8 + padding) + (24 + 0 + padding) = 56

System.out.println("fullSizeOf(new String()) = " + fullSizeOf(new String()));

// (16 + 4 + 4 + 8 + padding) = 32

System.out.println("sizeOf(new String('a')) = " + sizeOf(new String("a")));

// (16 + 4 + 4 + 8 +padding) + (24 + 2 + padding) = 64

System.out.println("fullSizeOf(new String('a')) = " + fullSizeOf(new String("a")));

System.out.println("-------------------原始類型數組對象---------------------------");

// 24 bytes + 0*1 + 0 = 24 數組長度為 0,所以僅僅有對象頭的長度

System.out.println("sizeOf(new byte[0]) = " + sizeOf(new byte[0]));

System.out.println("fullSizeOf(new byte[0]) = " + fullSizeOf(new byte[0]));

// 24 + 1*1 + padding = 32

System.out.println("sizeOf(new byte[1]) = " + sizeOf(new byte[1]));

System.out.println("fullSizeOf(new byte[1]) = " + fullSizeOf(new byte[1]));

// 24 + 1*2 + padding = 32

System.out.println("sizeOf(new char[1]) = " + sizeOf(new char[1]));

System.out.println("fullSizeOf(new char[1]) = " + fullSizeOf(new char[1]));

// 24 + 9*1 + padding = 40

System.out.println("sizeOf(new byte[9]) = " + sizeOf(new byte[9]));

System.out.println("fullSizeOf(new byte[9]) = " + fullSizeOf(new byte[9]));

System.out.println("--------------------引用類型數組對象--------------------------");

// 24 bytes + 0*8 + 0 = 24 數組長度為 0

System.out.println("sizeOf(new Integer[0]) = " + sizeOf(new Integer[0]));

System.out.println("fullSizeOf(new Integer[0]) = " + fullSizeOf(new Integer[0]));

// 24 bytes + 1*8 + 0 = 32 引用對象 64-bit JVM 占用 8 bytes

System.out.println("sizeOf(new Integer[1]) = " + sizeOf(new Integer[1]));

System.out.println("fullSizeOf(new Integer[1]) = " + fullSizeOf(new Integer[1]));

// 24 bytes + 2*8 + padding = 40

System.out.println("sizeOf(new Integer[1]) = " + sizeOf(new Integer[1]));

System.out.println("fullSizeOf(new Integer[1]) = " + fullSizeOf(new Integer[1]));

// 24 + 3*8 + padding = 48

System.out.println("sizeOf(new Integer[3]) = " + sizeOf(new Integer[3]));

System.out.println("fullSizeOf(new Integer[3]) = " + fullSizeOf(new Integer[3]));

System.out.println("-------------------自己定義數組對象---------------------------");

// 16 + (4+8) + padding = 32

System.out.println("sizeOf(new B()) = " + sizeOf(new B()));

System.out.println("fullSizeOf(new B()) = " + fullSizeOf(new B()));

// 24 + 0*8 + padding = 24 引用對象 64-bit JVM 占用 8 bytes,

// 由于沒創建真實的 new B()所以 B類內部數據還未占用空間

System.out.println("sizeOf(new B[0]) = " + sizeOf(new B[0]));

System.out.println("fullSizeOf(new B[0]) = " + fullSizeOf(new B[0]));

// 24 + 1*8 + padding = 32

System.out.println("sizeOf(new B[1]) = " + sizeOf(new B[1]));

System.out.println("fullSizeOf(new B[1]) = " + fullSizeOf(new B[1]));

// 24 + 2*8 + padding = 40

System.out.println("sizeOf(new B[2]) = " + sizeOf(new B[2]));

System.out.println("fullSizeOf(new B[2]) = " + fullSizeOf(new B[2]));

// 24 + 3*8 + padding = 48

System.out.println("sizeOf(new B[3]) = " + sizeOf(new B[3]));

System.out.println("fullSizeOf(new B[3]) = " + fullSizeOf(new B[3]));

System.out.println("-------------------復合對象---------------------------");

// 16 + (4+8) + padding = 32 sizeOf 僅僅計算單層次占用空間大小

System.out.println("sizeOf(new C()) = " + sizeOf(new C()));

// (16 + (4+8) + padding1) + (24 + 2*8 + padding2) + 2*(16 + (4+8) + padding3) = 136

// 遞歸計算當前對象占用空間總大小,包含當前類和超類的實例字段大小以及實例字段引用對象大小

System.out.println("fullSizeOf(new C()) = " + fullSizeOf(new C()));

System.out.println("-------------------繼承關系---------------------------");

// 涉及繼承關系的時候有一個最主要的規則:首先存放父類中的成員,接著才是子類中的成員, 父類也要依照 8 byte 規定

// 16 + 1 + padding = 24

System.out.println("sizeOf(new D()) = " + sizeOf(new D()));

System.out.println("fullSizeOf(new D()) = " + fullSizeOf(new D()));

// 16 + 父類(1 + padding1) + 1 + padding2 = 32

System.out.println("sizeOf(new E()) = " + sizeOf(new E()));

System.out.println("fullSizeOf(new E()) = " + fullSizeOf(new E()));

}

public static class A {

int a;

Integer b;

}

public static class B {

int a;

Integer b;

}

public static class C{

int c;

B[] b = new B[2];

// 初始化

C() {

for (int i = 0; i < b.length; i++) {

b[i] = new B();

}

}

}

public static class D {

byte d1;

}

public static class E extends D {

byte e1;

}

}

執行:

假設在 IDE 執行時須要設置 JVM 參數:?-javaagent:target/SizeOfAgent.jar -XX:-UseCompressedOops;

假設在命令行執行命令:?java -javaagent:sizeofag.jar

-XX:-UseCompressedOops 主類名稱。

測試結果:

------------------空對象----------------------------

sizeOf(new Object()) = 16

fullSizeOf(new Object()) = 16

----------------非空對象含有原始類型、引用類型------------------------------

sizeOf(new A()) = 32

fullSizeOf(new A()) = 32

sizeOf(new Integer(1)) = 24

sizeOf(new String()) = 32

fullSizeOf(new String()) = 56

sizeOf(new String('a')) = 32

fullSizeOf(new String('a')) = 64

-------------------原始類型數組對象---------------------------

sizeOf(new byte[0]) = 24

fullSizeOf(new byte[0]) = 24

sizeOf(new byte[1]) = 32

fullSizeOf(new byte[1]) = 32

sizeOf(new char[1]) = 32

fullSizeOf(new char[1]) = 32

sizeOf(new byte[9]) = 40

fullSizeOf(new byte[9]) = 40

--------------------引用類型數組對象--------------------------

sizeOf(new Integer[0]) = 24

fullSizeOf(new Integer[0]) = 24

sizeOf(new Integer[1]) = 32

fullSizeOf(new Integer[1]) = 32

sizeOf(new Integer[1]) = 32

fullSizeOf(new Integer[1]) = 32

sizeOf(new Integer[3]) = 48

fullSizeOf(new Integer[3]) = 48

-------------------自己定義數組對象---------------------------

sizeOf(new B()) = 32

fullSizeOf(new B()) = 32

sizeOf(new B[0]) = 24

fullSizeOf(new B[0]) = 24

sizeOf(new B[1]) = 32

fullSizeOf(new B[1]) = 32

sizeOf(new B[2]) = 40

fullSizeOf(new B[2]) = 40

sizeOf(new B[3]) = 48

fullSizeOf(new B[3]) = 48

-------------------復合對象---------------------------

sizeOf(new C()) = 48

fullSizeOf(new C()) = 152

-------------------繼承關系---------------------------

sizeOf(new D()) = 24

fullSizeOf(new D()) = 24

sizeOf(new E()) = 32

fullSizeOf(new E()) = 32

測試類中復合對象計算可能較為麻煩, 能夠參照下圖較為清楚地看出 new C() 的占用空間計算:

52f37cbda137270d0d267a4338807d51.png

六. 總結

總體的 Java 對象是依照一定規則進行的。 清楚了 JVM 對象的內存布局和分配規則。 計算 Java 對象的大小就比較簡單了。

Java 不像 C++ 能夠提供對象大小, 這是 Java 語言的設計初衷(自己主動內存管理), 可是隨著對 Java 的深入了解。 又到了對 JVM (使用 C、C++ 實現) 底層實現的問題上。

本文的參考資料為 2007 年的, 至今已有 9 年, 參考資料內容至今還是有效的,JVM 相關的東西變動確實小,挺有意思的

七. 參考資料

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/393334.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/393334.shtml
英文地址,請注明出處:http://en.pswp.cn/news/393334.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

源于十年來的點滴積累——《變革中的思索》印行出版

源于歸國十年來的點滴積累, 集結成書的《變革中的思索》&#xff0c;日前由電子工業出版社刊印出版。 這本書共有五個章節&#xff0c;分別是解碼創新、中國智造、管理心得、我和微軟、心靈記憶——前三章偏重技術&#xff0c;更多理性的思考; 后兩章則工作生活中的所見所聞&am…

SpringBoot聲明式事務

目錄 事務的基本特征隔離級別傳播行為Transcation事務的基本特征&#xff08;ACID&#xff09; Atomic&#xff08;原子性&#xff09; 事務中包含的操作被看作一個整體的業務單元&#xff0c;這個業務單元中的操作要么全部成功&#xff0c;要么全部失敗&#xff0c;不會出現部…

leetcode1437. 是否所有 1 都至少相隔 k 個元素

給你一個由若干 0 和 1 組成的數組 nums 以及整數 k。如果所有 1 都至少相隔 k 個元素&#xff0c;則返回 True &#xff1b;否則&#xff0c;返回 False 。 示例 1&#xff1a; 輸入&#xff1a;nums [1,0,0,0,1,0,0,1], k 2 輸出&#xff1a;true 解釋&#xff1a;每個 1 …

數據結構教程網盤鏈接_數據結構101:鏈接列表

數據結構教程網盤鏈接by Kevin Turney凱文特尼(Kevin Turney) Like stacks and queues, Linked Lists are a form of a sequential collection. It does not have to be in order. A Linked list is made up of independent nodes that may contain any type of data. Each no…

多線程之間的通信(等待喚醒機制、Lock 及其它線程的方法)

一、多線程之間的通信。 就是多個線程在操作同一份數據&#xff0c; 但是操作的方法不同。     如&#xff1a; 對于同一個存儲塊&#xff0c;其中有兩個存儲位&#xff1a;name sex&#xff0c; 現有兩個線程&#xff0c;一個向其中存放數據&#xff0c;一個打印其中的數…

Linux iptables 配置詳解

一、配置一個filter表的防火墻 1. 查看本機關于 iptables 的設置情況 # iptables -L -n Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) …

06 Nginx

1.檢查linux上是否通過yum安裝了nginx rpm -qi nginx2.解決安裝nginx所依賴包 yum install gcc patch libffi-devel python-devel zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel ope…

java編寫安卓程序代碼,安卓:從Android的Java源代碼code創建UML

i am looking for a program that can create automatically an Uml from my Java-Android source code.I have tested ArgoUml, but it does not support Android.Have any one a suggestion?Thanks!解決方案I can second what Tom Morris wrote in the comment above. Even …

leetcode1052. 愛生氣的書店老板(滑動窗口)

今天&#xff0c;書店老板有一家店打算試營業 customers.length 分鐘。每分鐘都有一些顧客&#xff08;customers[i]&#xff09;會進入書店&#xff0c;所有這些顧客都會在那一分鐘結束后離開。 在某些時候&#xff0c;書店老板會生氣。 如果書店老板在第 i 分鐘生氣&#xf…

amazon alexa_在Amazon Alexa上推出freeCodeCamp編碼瑣事測驗

amazon alexaNow you can learn coding concepts hands-free using an Amazon Echo.現在&#xff0c;您可以使用Amazon Echo免提學習編碼概念。 freeCodeCamp.org contributor David Jolliffe created a quiz game with questions on JavaScript, CSS, networking, and comput…

第一類第二類丟失更新

第一類丟失更新 A事務撤銷時&#xff0c;把已經提交的B事務的更新數據覆蓋了。這種錯誤可能造成很嚴重的問題&#xff0c;通過下面的賬戶取款轉賬就可以看出來&#xff1a; 時間 取款事務A 轉賬事務B T1 開始事務 T2 開始事務 T3 查詢賬戶余額為1000元 …

oracle數據字典表與視圖

oracle數據字典表與視圖 數據字典是數據的數據&#xff0c;也就是元數據。描述了數據庫的物理與邏輯存儲與相應的信息。模式中對象的定義信息&#xff0c;安全信息&#xff0c;完整性約束信息&#xff0c;和部分的性能監控信息等。數據字典表 與視圖存儲在system表空間中的。有…

團隊作業——項目Alpha版本發布

---恢復內容開始--- https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/homework/3329 <作業要求的鏈接> Gorious Computer <寫上團隊名稱> 發布項目α版本&#xff0c;對項目…

java臟字過濾_臟字過濾

1.[文件]SensitiveWordFilter.java ~ 7KB下載(141)package com.forgov.sharpc.infrastruture.util;import static java.util.Collections.sort;import java.util.ArrayList;import java.util.Collection;import java.util.Comparator;import java.util.HashSet;import java.uti…

react中使用構建緩存_完整的React課程:如何使用React構建聊天室應用

react中使用構建緩存In this video course, youll learn React by building a chat room app.在本視頻課程中&#xff0c;您將通過構建聊天室應用程序來學習React。 By the end of the video, youll have a solid understanding of React.js and have your very own chat room…

leetcode1509. 三次操作后最大值與最小值的最小差

給你一個數組 nums &#xff0c;每次操作你可以選擇 nums 中的任意一個元素并將它改成任意值。 請你返回三次操作后&#xff0c; nums 中最大值與最小值的差的最小值。 示例 1&#xff1a; 輸入&#xff1a;nums [5,3,2,4] 輸出&#xff1a;0 解釋&#xff1a;將數組 [5,3,…

MySQL異步復制

準備&#xff1a;主備庫版本一致&#xff0c;正常安裝軟件。 1、主庫上設置一個復制使用的賬戶&#xff1a; mysql> grant replication slave on *.* to rep1192.168.100.136 identified by dbking; Query OK, 0 rows affected (0.18 sec) mysql> select user,host,passw…

開源一個爬取redmine數據的測試報告系統

背景 軟件測試的最后有一道比較繁瑣的工作&#xff0c;就是編寫測試報告。手寫測試報告在數據統計和分析上面要耗費比較大的事件和精力。之前工作室使用mantis管理bug缺陷。公司有內部有個系統&#xff0c;可以直接從mantis上面獲取數據并進行統計&#xff0c;生成一份測試報告…

java cxf 雙向通訊_CXF 在spring boot 2 發布多個服務

0. 問題來源之前配置cxf服務端都是在spring 3以下&#xff0c;后來使用spring mvc 還都是基于xml的配置文件模式&#xff0c;在springboot模式下&#xff0c;實現起來更為簡單了。此次記錄下spring boot 2下的實現方式。1. 準備工作項目中&#xff0c;直接拉入spring boot cxf相…

小程序 堅屏_如何構建堅如磐石的應用程序

小程序 堅屏不同的應用程序設計選項概述 (An overview of different app design options) When we design software, we constantly think about error cases. Errors have a huge impact on the way we design and architecture a solution. So much so, in fact, that there …