Cara Mendapatkan Ukuran Objek di Java

1. Ikhtisar

Tidak seperti C / C ++ di mana kita bisa menggunakan metode sizeof () untuk mendapatkan ukuran objek dalam byte, tidak ada padanan sebenarnya dari metode seperti itu di Java.

Di artikel ini, kami akan mendemonstrasikan bagaimana kami masih bisa mendapatkan ukuran objek tertentu.

2. Konsumsi Memori di Jawa

Meskipun tidak ada ukuran operator di Java, kami sebenarnya tidak membutuhkannya. Semua tipe primitif memiliki ukuran standar, dan biasanya tidak ada pad atau byte alignment. Namun, ini tidak selalu mudah.

Meskipun primitif harus berperilaku seolah-olah memiliki ukuran resmi, JVM dapat menyimpan data dengan cara apa pun yang diinginkan secara internal, dengan sejumlah padding atau overhead . Ia dapat memilih untuk menyimpan boolean [] dalam potongan 64-bit panjang seperti BitSet , mengalokasikan beberapa Objek sementara pada tumpukan atau mengoptimalkan beberapa variabel atau pemanggilan metode sama sekali tidak ada menggantikannya dengan konstanta, dll ... Tapi, selama Program memberikan hasil yang sama, itu baik-baik saja.

Mempertimbangkan juga dampak cache perangkat keras dan OS (data kami dapat digandakan pada setiap level cache), itu berarti bahwa kami hanya dapat memprediksi konsumsi RAM secara kasar .

2.1. Objek, Referensi dan Kelas Wrapper

Ukuran objek minimum adalah 16 byte untuk JDK 64-bit modern karena objek memiliki header 12-byte, ditambah dengan kelipatan 8 byte. Dalam JDK 32-bit, overhead adalah 8 byte, digabungkan ke kelipatan 4 byte.

Referensi memiliki ukuran tipikal 4 byte pada platform 32-bit dan pada platform 64-bit dengan batas heap kurang dari 32 Gb ( -Xmx32G ), dan 8 byte untuk batas ini di atas 32 Gb.

Artinya, JVM 64-bit biasanya membutuhkan ruang heap 30-50% lebih banyak.

Yang terutama relevan adalah untuk dicatat bahwa tipe kotak, array, String dan wadah lain seperti array multidimensi adalah memori yang mahal karena mereka menambahkan overhead tertentu . Sebagai contoh, ketika kita membandingkan int primitive (yang hanya mengkonsumsi 4 byte) dengan objek Integer yang membutuhkan 16 byte, kita melihat bahwa ada 300% overhead memori.

3. Memperkirakan Ukuran Objek Menggunakan Instrumentasi

Salah satu cara untuk mendapatkan perkiraan ukuran objek di Java adalah dengan menggunakan metode getObjectSize (Object) dari antarmuka Instrumentasi yang diperkenalkan di Java 5.

Seperti yang bisa kita lihat dalam dokumentasi Javadoc, metode ini menyediakan "pendekatan khusus implementasi" dari ukuran objek yang ditentukan. Perlu dicatat bahwa ada potensi inklusi overhead dalam ukuran dan nilainya dapat berbeda selama pemanggilan JVM tunggal.

Pendekatan ini hanya mendukung estimasi ukuran dari objek itu sendiri dan bukan ukuran dari objek yang direferensikannya . Untuk memperkirakan ukuran total objek, kita memerlukan kode yang akan memeriksa referensi tersebut dan menghitung perkiraan ukurannya.

3.1. Membuat Agen Instrumentasi

Untuk memanggil Instrumentation.getObjectSize (Object) untuk mendapatkan ukuran objek, kita harus bisa mengakses instance Instrumentasi terlebih dahulu. Kita perlu menggunakan agen instrumentasi dan ada dua cara untuk melakukannya, seperti yang dijelaskan dalam dokumentasi untuk paket java.lang.instrument .

Agen instrumentasi dapat ditentukan melalui baris perintah atau kita dapat menggunakannya dengan JVM yang sudah berjalan . Kami akan fokus pada yang pertama.

Untuk menentukan agen instrumentasi melalui command-line , kita memerlukan implementasi metode premain kelebihan beban yang akan dipanggil pertama kali oleh JVM saat menggunakan instrumentasi. Selain itu, kita perlu mengekspos metode statis untuk dapat mengakses Instrumentation.getObjectSize (Object) .

Sekarang mari buat kelas InstrumentationAgent :

public class InstrumentationAgent { private static volatile Instrumentation globalInstrumentation; public static void premain(final String agentArgs, final Instrumentation inst) { globalInstrumentation = inst; } public static long getObjectSize(final Object object) { if (globalInstrumentation == null) { throw new IllegalStateException("Agent not initialized."); } return globalInstrumentation.getObjectSize(object); } }

Sebelum kita membuat JAR untuk agen ini, kita perlu memastikan bahwa metafile sederhana, MANIFEST.MF disertakan di dalamnya :

Premain-class: com.baeldung.objectsize.InstrumentationAgent

Sekarang kita dapat membuat JAR Agen dengan file MANIFEST.MF disertakan. Salah satu caranya adalah melalui baris perintah:

javac InstrumentationAgent.java jar cmf MANIFEST.MF InstrumentationAgent.jar InstrumentationAgent.class

3.2. Contoh Kelas

Mari kita lihat ini beraksi dengan membuat kelas dengan objek sampel yang akan menggunakan kelas agen kami:

public class InstrumentationExample { public static void printObjectSize(Object object) { System.out.println("Object type: " + object.getClass() + ", size: " + InstrumentationAgent.getObjectSize(object) + " bytes"); } public static void main(String[] arguments) { String emptyString = ""; String string = "Estimating Object Size Using Instrumentation"; String[] stringArray = { emptyString, string, "com.baeldung" }; String[] anotherStringArray = new String[100]; List stringList = new ArrayList(); StringBuilder stringBuilder = new StringBuilder(100); int maxIntPrimitive = Integer.MAX_VALUE; int minIntPrimitive = Integer.MIN_VALUE; Integer maxInteger = Integer.MAX_VALUE; Integer minInteger = Integer.MIN_VALUE; long zeroLong = 0L; double zeroDouble = 0.0; boolean falseBoolean = false; Object object = new Object(); class EmptyClass { } EmptyClass emptyClass = new EmptyClass(); class StringClass { public String s; } StringClass stringClass = new StringClass(); printObjectSize(emptyString); printObjectSize(string); printObjectSize(stringArray); printObjectSize(anotherStringArray); printObjectSize(stringList); printObjectSize(stringBuilder); printObjectSize(maxIntPrimitive); printObjectSize(minIntPrimitive); printObjectSize(maxInteger); printObjectSize(minInteger); printObjectSize(zeroLong); printObjectSize(zeroDouble); printObjectSize(falseBoolean); printObjectSize(Day.TUESDAY); printObjectSize(object); printObjectSize(emptyClass); printObjectSize(stringClass); } public enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY } }

Agar ini berfungsi, kita perlu menyertakan opsi - javaagent dengan jalur ke agen JAR saat menjalankan aplikasi kita :

VM Options: -javaagent:"path_to_agent_directory\InstrumentationAgent.jar"

Output dari menjalankan kelas kita akan menunjukkan perkiraan ukuran objek:

Object type: class java.lang.String, size: 24 bytes Object type: class java.lang.String, size: 24 bytes Object type: class [Ljava.lang.String;, size: 32 bytes Object type: class [Ljava.lang.String;, size: 416 bytes Object type: class java.util.ArrayList, size: 24 bytes Object type: class java.lang.StringBuilder, size: 24 bytes Object type: class java.lang.Integer, size: 16 bytes Object type: class java.lang.Integer, size: 16 bytes Object type: class java.lang.Integer, size: 16 bytes Object type: class java.lang.Integer, size: 16 bytes Object type: class java.lang.Long, size: 24 bytes Object type: class java.lang.Double, size: 24 bytes Object type: class java.lang.Boolean, size: 16 bytes Object type: class com.baeldung.objectsize.InstrumentationExample$Day, size: 24 bytes Object type: class java.lang.Object, size: 16 bytes Object type: class com.baeldung.objectsize.InstrumentationExample$1EmptyClass, size: 16 bytes Object type: class com.baeldung.objectsize.InstrumentationExample$1StringClass, size: 16 bytes

4. Kesimpulan

Dalam artikel ini, kami menjelaskan bagaimana memori digunakan oleh tipe tertentu di Java, bagaimana JVM menyimpan data dan menekankan hal-hal yang dapat mempengaruhi konsumsi memori total. Kami kemudian mendemonstrasikan bagaimana kami bisa dalam praktiknya mendapatkan perkiraan ukuran objek Java.

Seperti biasa, kode lengkap terkait artikel ini dapat ditemukan di proyek GitHub.