Memperkirakan Ukuran Objek Java dengan Instrumentasi

Sebagian besar pengembang Java yang berasal dari latar belakang C / C ++ mungkin pernah menginginkan Java yang setara dengan sizeof (). Meskipun Java tidak memiliki ukuran sebenarnya () yang setara, antarmuka Instrumentasi yang diperkenalkan dengan J2SE5 dapat digunakan untuk mendapatkan perkiraan ukuran objek tertentu melalui metode getObjectSize (Object). Meskipun pendekatan ini hanya mendukung objek yang dianggap sendiri dan tidak memperhitungkan ukuran objek yang direferensikan, kode dapat dibangun untuk melintasi referensi tersebut dan menghitung perkiraan ukuran total.

Antarmuka Instrumental menyediakan beberapa metode, tetapi fokus posting ini adalah metode getObjectSize (Object). Dokumentasi Javadoc metode ini menjelaskan metode tersebut:

Mengembalikan perkiraan khusus implementasi dari jumlah penyimpanan yang dikonsumsi oleh objek yang ditentukan. Hasilnya mungkin mencakup beberapa atau semua overhead objek, dan dengan demikian berguna untuk perbandingan dalam implementasi tetapi tidak di antara implementasi. Perkiraan dapat berubah selama satu pemanggilan JVM.

Deskripsi ini memberi tahu kita apa yang dilakukan metode (memberikan "pendekatan khusus implementasi" dari ukuran objek yang ditentukan), potensi penyertaan overhead dalam ukuran yang diperkirakan, dan nilai yang berpotensi berbeda selama pemanggilan JVM tunggal.

Cukup jelas bahwa seseorang dapat memanggil Instrumentation.getObjectSize(Object)sebuah objek untuk mendapatkan perkiraan ukurannya, tetapi bagaimana cara mengakses sebuah instance Instrumentationdi tempat pertama? Dokumentasi paket untuk paket java.lang.instrument menyediakan jawabannya (dan merupakan contoh deskripsi paket Javadoc yang efektif).

Dokumentasi tingkat paket untuk paket java.lang.instrument menjelaskan dua cara implementasi memungkinkan penggunaan instrumentasi JVM. Pendekatan pertama (dan yang disorot dalam posting ini) adalah menentukan agen instrumentasi melalui baris perintah. Pendekatan kedua adalah menggunakan agen instrumentasi dengan JVM yang sudah berjalan. Dokumentasi paket selanjutnya menjelaskan gambaran umum tingkat tinggi tentang penggunaan setiap pendekatan. Dalam setiap pendekatan, entri khusus diperlukan dalam file manifes JAR agen untuk menentukan kelas agen: Premain-Classuntuk pendekatan baris perintah dan Agent-Classuntuk pendekatan permulaan pasca-JVM. Kelas agen memerlukan metode khusus yang diterapkan untuk kedua kasus: premainuntuk startup baris perintah atau agentmainawal JVM startup.

Daftar kode berikutnya menampilkan kode Java untuk agen instrumentasi. Kelas tersebut menyertakan metode premain(agen baris perintah) dan metode agentmain(agen startup JVM), meskipun hanya yang premainakan didemonstrasikan dalam posting ini.

package dustin.examples; import static java.lang.System.out; import java.lang.instrument.Instrumentation; /** * Simple example of an Instrumentation Agent adapted from blog post * "Instrumentation: querying the memory usage of a Java object" * (//www.javamex.com/tutorials/memory/instrumentation.shtml). */ public class InstrumentationAgent { /** Handle to instance of Instrumentation interface. */ private static volatile Instrumentation globalInstrumentation; /** * Implementation of the overloaded premain method that is first invoked by * the JVM during use of instrumentation. * * @param agentArgs Agent options provided as a single String. * @param inst Handle to instance of Instrumentation provided on command-line. */ public static void premain(final String agentArgs, final Instrumentation inst) { out.println("premain..."); globalInstrumentation = inst; } /** * Implementation of the overloaded agentmain method that is invoked for * accessing instrumentation of an already running JVM. * * @param agentArgs Agent options provided as a single String. * @param inst Handle to instance of Instrumentation provided on command-line. */ public static void agentmain(String agentArgs, Instrumentation inst) { out.println("agentmain..."); globalInstrumentation = inst; } /** * Provide the memory size of the provided object (but not it's components). * * @param object Object whose memory size is desired. * @return The size of the provided object, not counting its components * (described in Instrumentation.getObjectSize(Object)'s Javadoc as "an * implementation-specific approximation of the amount of storage consumed * by the specified object"). * @throws IllegalStateException Thrown if my Instrumentation is null. */ public static long getObjectSize(final Object object) { if (globalInstrumentation == null) { throw new IllegalStateException("Agent not initialized."); } return globalInstrumentation.getObjectSize(object); } } 

Kelas agen di atas memperlihatkan metode yang tersedia secara statis untuk mengakses Instrumentation.getObjectSize(Object). Daftar kode berikutnya menunjukkan 'aplikasi' sederhana yang memanfaatkannya.

package dustin.examples; import static java.lang.System.out; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Calendar; import java.util.List; /** * Build up some sample objects and throw them at the Instrumentation example. * * Might run this class as shown next: * java -javaagent:dist\agent.jar -cp dist\agent.jar dustin.examples.InstrumentSampleObjects * * @author Dustin */ public class InstrumentSampleObjects { public enum Color { RED, WHITE, YELLOW } /** * Print basic details including size of provided object to standard output. * * @param object Object whose value and size are to be printed to standard * output. */ public static void printInstrumentationSize(final Object object) { out.println( "Object of type '" + object.getClass() + "' has size of " + InstrumentationAgent.getObjectSize(object) + " bytes."); } /** * Main executable function. * * @param arguments Command-line arguments; none expected. */ public static void main(final String[] arguments) { final StringBuilder sb = new StringBuilder(1000); final boolean falseBoolean = false; final int zeroInt = 0; final double zeroDouble = 0.0; final Long zeroLong = 0L; final long zeroLongP = 0L; final Long maxLong = Long.MAX_VALUE; final Long minLong = Long.MIN_VALUE; final long maxLongP = Long.MAX_VALUE; final long minLongP = Long.MIN_VALUE; final String emptyString = ""; final String string = "ToBeOrNotToBeThatIsTheQuestion"; final String[] strings = {emptyString, string, "Dustin"}; final String[] moreStrings = new String[1000]; final List someStrings = new ArrayList(); final EmptyClass empty = new EmptyClass(); final BigDecimal bd = new BigDecimal("999999999999999999.99999999"); final Calendar calendar = Calendar.getInstance(); printInstrumentationSize(sb); printInstrumentationSize(falseBoolean); printInstrumentationSize(zeroInt); printInstrumentationSize(zeroDouble); printInstrumentationSize(zeroLong); printInstrumentationSize(zeroLongP); printInstrumentationSize(maxLong); printInstrumentationSize(maxLongP); printInstrumentationSize(minLong); printInstrumentationSize(minLongP); printInstrumentationSize(maxLong); printInstrumentationSize(maxLongP); printInstrumentationSize(emptyString); printInstrumentationSize(string); printInstrumentationSize(strings); printInstrumentationSize(moreStrings); printInstrumentationSize(someStrings); printInstrumentationSize(empty); printInstrumentationSize(bd); printInstrumentationSize(calendar); printInstrumentationSize(Color.WHITE); } } 

Untuk menggunakan agen instrumentasi melalui start-up baris perintah, saya perlu memastikan bahwa metafile sederhana disertakan dalam JAR agen. Ini mungkin terlihat seperti berikut dalam daftar kode berikutnya untuk kelas agen dalam case ( dustin.examples.InstrumentationAgent). Meskipun saya hanya memerlukan Premain-classentri untuk startup baris perintah dari agen, saya telah menyertakan Agent-classsebagai contoh cara menggunakan agen startup posting JVM. Tidak ada salahnya untuk memiliki keduanya hadir sama seperti tidak ada salahnya untuk memiliki keduanya premaindan agentmainmetode yang ditentukan dalam kelas objek. Ada aturan yang ditentukan yang mana di antaranya pertama kali dicoba berdasarkan jenis agen yang digunakan.

Premain-class: dustin.examples.InstrumentationAgent Agent-class: dustin.examples.InstrumentationAgent 

Untuk menempatkan file manifes ini ke dalam JAR, saya dapat menggunakan jar cmfwith nama file manifes dan kelas Java yang akan diarsipkan ke JAR. Namun, ini bisa dibilang lebih mudah dilakukan dengan Ant dan tentunya lebih disukai karena berulang kali melakukannya. Penggunaan sederhana tugas Ant jar dengan sub-elemen manifes ditampilkan berikutnya.

Dengan JAR yang dibangun, saya dapat dengan mudah menjalankannya dengan peluncur Java dan menentukan agen Java ( -javaagent):

java -javaagent:dist\Instrumentation.jar -cp Instrumentation.jar dustin.examples.InstrumentSampleObjects 

Cuplikan layar berikutnya menunjukkan keluaran.

Output di atas menunjukkan beberapa perkiraan ukuran berbagai objek seperti BigDecimal, Calendar, dan lainnya.

Ada beberapa sumber berguna terkait dengan topik posting ini. Proyek java.sizeOf adalah "agen java kecil yang menggunakan paket java.lang.Instrument yang diperkenalkan di Java 5 dan dirilis di bawah lisensi GPL." Heinz M. Kabutz's Instrumentation Memory Counter memberikan contoh yang jauh lebih canggih daripada posting saya tentang penggunaan antarmuka Instrumentasi untuk memperkirakan ukuran objek. Instrumentasi: menanyakan penggunaan memori objek Java memberikan gambaran umum yang bagus tentang antarmuka ini dan menyediakan tautan ke agen Classmexer, "agen instrumentasi Java sederhana yang menyediakan beberapa panggilan praktis untuk mengukur penggunaan memori objek Java dari dalam aplikasi. " Tulisan Berapa banyak memori yang dikonsumsi objek java? dan Memperkirakan penggunaan memori dari objek java juga terkait.

Pengeposan asli tersedia di //marxsoftware.blogspot.com/ (Terinspirasi oleh Acara Aktual)

Artikel ini, "Memperkirakan Ukuran Objek Java dengan Instrumentasi", awalnya diterbitkan oleh JavaWorld.