日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java统计空间占用_JVM —— Java 对象占用空间大小计算

發布時間:2023/12/9 java 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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() 的占用空間計算:

六. 總結

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

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

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

七. 參考資料

總結

以上是生活随笔為你收集整理的java统计空间占用_JVM —— Java 对象占用空间大小计算的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。