測量java對象大小的demo(java 對象大小)

本文目錄一覽:

java中怎麼算一個對象的空間大小

Object流

直接將Object寫入或讀出

也叫做對象的序列化:把一個Object直接轉換成位元組流寫到硬盤上,或者直接寫到網絡上去

這裡有一個類T:

class T implements Serializable { // 注意,必須要實現Serializable接口,才是可序列化的

int i = 10;

int j = 9;

double d = 2.3;

int k = 15;

}

這個類裏面的成員變量3個int,1個double,int是4位元組,double是8位元組

所以對象的大小絕對不會小於20位元組,但是T肯定是從Object類繼承,那麼繼承下來這些內容也

占空間,比如方法什麼的,所以肯定要大於20位元組了

運行下面這個類:

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;

public class Test {

public static void main(String[] args) {

T t = new T();

try {

FileOutputStream fos = new FileOutputStream(“d:/abc.txt”);

ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeObject(t);

oos.flush();

oos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

直接將T對象通過Object流寫到了D盤的名為abc.txt的文件裏面

一個空文本文件是0位元組,找到這個文件以後查看它的屬性,我這裡是67 位元組,

那麼這個對象就是67 位元組

現在在T類中添加一些其他內容,那麼再次輸出,位元組數肯定就比原來大了,它就是把整個對象轉換成

位元組,寫入了文件,這個應該算是比較好的方式了,但是我們無法特別精確的知道對象中哪些內容各自

佔用多少空間,因為那是Java虛擬機的事了,我學的沒那麼深入,水平有限

當然,把一個對象寫進去,也可以讀出來:

FileInputStream fis = new FileInputStream(“”);

ObjectInputStream ois = new ObjectInputStream(fis);

// 當成Object讀出來的,強轉成T類型

T tReaded = (T)ois.readObject();

System.out.println(tReaded.i + ” ” + tReaded.j + ” ” + tReaded.d + ” ” + tReaded.k);

發現打印出的成員變量的值,還是存進去這個對象的值

怎麼確定Java對象的大小

普通對象的結構如下,按64位機器的長度計算

1. 對象頭(_mark), 8個位元組

2. Oop指針,如果是32G內存以下的,默認開啟對象指針壓縮,4個位元組

3. 數據區

4.Padding(內存對齊),按照8的倍數對齊

數組對象結構是

1. 對象頭(_mark), 8個位元組

2. Oop指針,如果是32G內存以下的,默認開啟對象指針壓縮,4個位元組

3. 數組長度,4個位元組

4. 數據區

5. Padding(內存對齊),按照8的倍數對齊

清楚了對象在內存的基本布局後,咱們說兩種計算Java對象大小的方法

1. 通過java.lang.instrument.Instrumentation的getObjectSize(obj)直接獲取對象的大小

2. 通過sun.misc.Unsafe對象的objectFieldOffset(field)等方法結合反射來計算對象的大小

java.lang.instrument.Instrumentation.getObjectSize()的方式

先講講java.lang.instrument.Instrumentation.getObjectSize()的方式,這種方法得到的是Shallow Size,即遇到引用時,只計算引用的長度,不計算所引用的對象的實際大小。如果要計算所引用對象的實際大小,可以通過遞歸的方式去計算。

java.lang.instrument.Instrumentation的實例必須通過指定javaagent的方式才能獲得,具體的步驟如下:

1. 定義一個類,提供一個premain方法: public static void premain(String agentArgs, Instrumentation instP)

2. 創建META-INF/MANIFEST.MF文件,內容是指定PreMain的類是哪個: Premain-Class: sizeof.ObjectShallowSize

3. 把這個類打成jar,然後用java -javaagent XXXX.jar XXX.main的方式執行

有興趣可以看下博主的:

如何計算Java對象所佔內存的大小

java中可以用.getBytes().length獲取字符串佔用內容的大小,原理是java中任何字符都採用Unicode編碼,所以衡量佔用內存大小採用佔用的位元組數。

舉例如下:

public class TestStringSize {

public static final void main(String[] args) {

System.out.println(“佔用內存大小:”+”學java”.getBytes().length);

}

}

輸出結果:

佔用內存大小:6 byte

如何計算java對象的大小

首先,我們先寫一段大家可能不怎麼寫或者認為不可能的代碼:一個類中,幾個類型都是private類型,沒有public方法,如何對這些屬性進行讀寫操作,看似不可能哦,為什麼,這違背了面向對象的封裝,其實在必要的時候,留一道後門可以使得語言的生產力更加強大,對象的序列化不會因為沒有public方法就無法保存成功吧,OK,我們簡單寫段代碼開個頭,逐步引入到怎麼樣去測試對象的大小,一下代碼非常簡單,相信不用我解釋什麼:

import java.lang.reflect.Field;

class NodeTest1 {

private int a = 13;

private int b = 21;

}

public class Test001 {

public static void main(String []args) {

NodeTest1 node = new NodeTest1();

Field []fields = NodeTest1.class.getDeclaredFields();

for(Field field : fields) {

field.setAccessible(true);

try {

int i = field.getInt(node);

field.setInt(node, i * 2);

System.out.println(field.getInt(node));

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

}

}

代碼最基本的意思就是:實例化一個NodeTest1這個類的實例,然後取出兩個屬性,分別乘以2,然後再輸出,相信大家會認為這怎麼可能,NodeTest1根本沒有public方法,代碼就在這裡,將代碼拷貝回去運行下就OK了,OK,現在不說這些了,運行結果為:

26

42

為什麼可以取到,是每個屬性都留了一道門,主要是為了自己或者外部接入的方便,相信看代碼自己仔細的朋友,應該知道門就在:field.setAccessible(true);代表這個域的訪問被打開,好比是一道後門打開了,呵呵,上面的方法如果不設置這個,就直接報錯。

看似和對象大小沒啥關係,不過這只是拋磚引玉,因為我們首先要拿到對象的屬性,才能知道對象的大小,對象如果沒有提供public方法我們也要知道它有哪些屬性,所以我們後面多半會用到這段類似的代碼哦!

對象測量大小的方法關鍵為java提供的(1.5過後才有):java.lang.instrument.Instrumentation,它提供了豐富的對結構的等各方面的跟蹤和對象大小的測量的API(本文只闡述對象大小的測量方法),於是乎我心喜了,不過比較噁心的是它是實例化類:sun.instrument.IntrumentationImpl是sun開頭的,這個鬼東西有點不好搞,翻開源碼構造方法是private類型,沒有任何getInstance的方法,寫這個類幹嘛?看來這個只能被JVM自己給初始化了,那麼怎麼將它自己初始化的東西取出來用呢,唯一能想到的就是agent代理,那麼我們先拋開代理,首先來寫一個簡單的對象測量方法:

步驟1:(先創建一個用於測試對象大小的處理類)

import java.lang.instrument.Instrumentation;

public class MySizeOf {

private static Instrumentation inst;

/**

*這個方法必須寫,在agent調用時會被啟用

*/

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

inst = instP;

}

/**

* 直接計算當前對象佔用空間大小,包括:當前類及超類的基本類型實例字段大小

* 引用類型實例字段引用大小、實例基本類型數組總佔用空間、實例引用類型數組引用本身佔用空間大小

* 但是不包括超類繼承下來的和當前類聲明的實例引用字段的對象本身的大小、實例引用數組引用的對象本身的大小

* 用來測量java對象的大小(這裡先理解這個大小是正確的,後面再深化)

*/

public static long sizeOf(Object o) {

if(inst == 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 inst.getObjectSize(o);

}

}

步驟2:上面我們寫好了agent的代碼,此時我們要將上面這個類編譯後打包為一個jar文件,並且在其包內部的META-INF/MANIFEST.MF文件中增加一行:Premain-Class: MySizeOf代表執行代理的全名,這裡的類名稱是沒有package的,如果你有package,那麼就寫全名,我們這裡假設打包完的jar包名稱為agent.jar(打包過程這裡簡單闡述,就不細說了),OK,繼續向下走:

步驟3:編寫測試類,測試類中寫:

public class TestSize {

public static void main(String []args) {

System.out.println(MySizeOf.sizeOf(new Integer(1)));

System.out.println(MySizeOf.sizeOf(new String(“a”)));

System.out.println(MySizeOf.sizeOf(new char[1]));

}

}

如何計算java中的對象object大小size

// 利用GC回收前與回收後的差值計算對象的大小:

class Foo{ // 32位OS類定義引用佔8 byte,64位OS佔用16 byte

   int x;  // 4 byte

   byte b; // 1 byte

}

public class Demo {

  public static void main(String args[]) {

  

    Foo foo= new Foo();

    Runtime.getRuntime().gc();

    long gcing = Runtime.getRuntime().freeMemory();

    Foo foo2= new Foo();

    long gced = Runtime.getRuntime().freeMemory();

    // 64位打印24,32位打印16 (注:是因為JVM底層內存都是以8 byte對齊的,即8的倍數)

    System.out.println(“Memory used:”+(gcing -gced )); 

    

  }

  

}

原創文章,作者:簡單一點,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/130276.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
簡單一點的頭像簡單一點
上一篇 2024-10-03 23:28
下一篇 2024-10-03 23:28

相關推薦

  • 面向對象編程、類和對象

    面向對象編程(Object-Oriented Programming, OOP)是一種編程方法,它將現實世界中的事物抽象為對象(Object),對象的屬性和方法被封裝成類(Clas…

    編程 2025-04-29
  • Akka 設置郵箱大小的方法和注意事項

    為了保障系統的穩定性和可靠性,Akka 允許用戶設置郵箱大小。本文將介紹如何在 Akka 中設置郵箱大小,並且提供一些注意事項,以幫助讀者解決可能遇到的問題。 一、設置郵箱大小 A…

    編程 2025-04-28
  • 谷歌瀏覽器窗口大小調整

    谷歌瀏覽器是當今最流行的網絡瀏覽器之一,它的窗口大小調整是用戶操作其中的一個重要部分。本文將從多個方面對谷歌瀏覽器窗口大小調整做詳細的闡述。 一、窗口大小調整的基礎操作 谷歌瀏覽器…

    編程 2025-04-28
  • Mapster:一個高性能的對象映射庫

    本文將深入介紹furion.extras.objectmapper.mapster,一個高性能的對象映射庫,解釋它是如何工作的以及如何在你的項目中使用它。 一、輕鬆地實現對象之間的…

    編程 2025-04-28
  • 矩陣比較大小的判斷方法

    本文將從以下幾個方面對矩陣比較大小的判斷方法進行詳細闡述: 一、判斷矩陣中心 在比較矩陣大小前,我們需要先確定矩陣中心的位置,一般採用以下兩種方法: 1.行列判斷法 int mid…

    編程 2025-04-28
  • 如何通過IDEA設置gradle的heap大小

    在IDEA中設置gradle的heap大小可以有效提高gradle編譯、運行等使用效率,本文將從以下幾個方面介紹如何通過IDEA設置gradle的heap大小。 一、設置gradl…

    編程 2025-04-28
  • Python返回對象類型

    Python是一種動態、解釋型、高級編程語言。Python是一種面向對象的語言,即所有的一切都是一個對象。 一、基本類型 Python中的基本類型有整數int、浮點數float、布…

    編程 2025-04-28
  • Python中通過對象不能調用類方法和靜態方法的解析

    當我們在使用Python編寫程序時,可能會遇到通過對象調用類方法和靜態方法失敗的問題,那麼這是為什麼呢?接下來,我們將從多個方面對這個問題進行詳細解析。 一、類方法和靜態方法的定義…

    編程 2025-04-27
  • Java Date時間大小比較

    本文將從多個角度詳細闡述Java中Date時間大小的比較,包含了時間字符串轉換、日期相減、使用Calendar比較、使用compareTo方法比較等多個方面。相信這篇文章能夠對你解…

    編程 2025-04-27
  • Python內置函數——查看對象內存

    本文將介紹Python內置函數中,在開發中查看對象內存的相關函數。 一、id()函數 id()函數是Python內置函數,用於返回對象的唯一標識符,也就是對象在內存中的地址。 nu…

    編程 2025-04-27

發表回復

登錄後才能評論