Saya memiliki aplikasi yang membaca file CSV dengan tumpukan baris data. Saya memberi pengguna ringkasan jumlah baris berdasarkan jenis data, tetapi saya ingin memastikan bahwa saya tidak membaca terlalu banyak baris data dan penyebabnya OutOfMemoryError
. Setiap baris diterjemahkan menjadi objek. Apakah ada cara mudah untuk mengetahui ukuran objek itu secara terprogram? Apakah ada referensi yang menentukan seberapa besar tipe primitif dan referensi objek untuk suatu VM
?
Saat ini, saya memiliki kode yang mengatakan membaca hingga 32.000 baris , tetapi saya juga ingin memiliki kode yang mengatakan membaca sebanyak mungkin baris sampai saya menggunakan memori 32MB . Mungkin itu pertanyaan yang berbeda, tapi saya masih ingin tahu.
Jawaban:
Anda dapat menggunakan paket java.lang.instrument
Kompilasi dan letakkan kelas ini dalam JAR:
Tambahkan yang berikut ke Anda
MANIFEST.MF
:Gunakan getObjectSize:
Diminta dengan:
sumber
byte[0]
,byte[1]
,byte[5]
,int[0]
,int[1]
,int[2]
menggunakan pendekatan yang Anda dijelaskan? Akan lebih baik, jika hasilnya termasuk overhead untuk panjang array dan penyelarasan memori.Anda harus menggunakan jol , alat yang dikembangkan sebagai bagian dari proyek OpenJDK.
Untuk mendapatkan ukuran primitif, referensi, dan elemen array, gunakan
VMSupport.vmDetails()
. Pada Oracle JDK 1.8.0_40 berjalan pada Windows 64-bit (digunakan untuk semua contoh berikut), metode ini kembaliAnda bisa mendapatkan ukuran dangkal dari instance objek menggunakan
ClassLayout.parseClass(Foo.class).toPrintable()
(opsional lewat instance ketoPrintable
). Ini hanya ruang yang dikonsumsi oleh satu instance dari kelas itu; itu tidak termasuk objek lain yang dirujuk oleh kelas itu. Itu tidak termasuk overhead VM untuk header objek, keselarasan bidang dan padding. Untukjava.util.regex.Pattern
:Anda bisa mendapatkan tampilan ringkasan ukuran mendalam dari instance objek menggunakan
GraphLayout.parseInstance(obj).toFootprint()
. Tentu saja, beberapa objek dalam tapak mungkin dibagikan (juga direferensikan dari objek lain), sehingga ini merupakan perkiraan berlebihan dari ruang yang dapat direklamasi ketika objek tersebut adalah sampah yang dikumpulkan. Untuk hasilPattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$")
(diambil dari jawaban ini ), jol melaporkan jejak total 1840 byte, di mana hanya 72 adalah contoh Pola itu sendiri.Jika Anda sebaliknya menggunakan
GraphLayout.parseInstance(obj).toPrintable()
, jol akan memberi tahu Anda alamat, ukuran, jenis, nilai, dan jalur dereferensi bidang untuk setiap objek yang direferensikan, meskipun itu biasanya terlalu banyak detail untuk berguna. Untuk contoh pola yang sedang berlangsung, Anda mungkin mendapatkan yang berikut ini. (Alamat kemungkinan akan berubah antar berjalan.)Entri "(sesuatu yang lain)" menggambarkan objek lain di heap yang bukan bagian dari grafik objek ini .
Dokumentasi jol terbaik adalah sampel jol dalam repositori jol. Sampel menunjukkan operasi jol umum dan menunjukkan bagaimana Anda dapat menggunakan jol untuk menganalisis VM dan internal pengumpul sampah.
sumber
vmDetails
sekarangVM.current().details()
.GraphLayout.parseInstance(instance).toFootprint()
saya merasa lebih berguna untuk memahami ukuran objekSaya tidak sengaja menemukan kelas java "jdk.nashorn.internal.ir.debug.ObjectSizeCalculator", sudah di jdk, yang mudah digunakan dan tampaknya cukup berguna untuk menentukan ukuran suatu objek.
hasil:
sumber
ObjectSizeCalculator
hanya didukung pada HotSpot VMBeberapa tahun yang lalu Javaworld memiliki artikel tentang menentukan ukuran komposit dan objek Java yang berpotensi bersarang , mereka pada dasarnya berjalan melalui pembuatan sizeof () implementasi di Jawa. Pendekatan ini pada dasarnya dibangun di atas karya lain di mana orang secara eksperimental mengidentifikasi ukuran primitif dan objek Java yang khas dan kemudian menerapkan pengetahuan itu ke metode yang secara rekursif berjalan grafik objek untuk menghitung ukuran total.
Itu selalu akan menjadi kurang akurat daripada implementasi C asli hanya karena hal-hal yang terjadi di belakang layar kelas tetapi itu harus menjadi indikator yang baik.
Atau proyek SourceForge tepat disebut sizeof yang menawarkan perpustakaan Java5 dengan sizeof () implementasi.
PS Jangan menggunakan pendekatan serialisasi, tidak ada korelasi antara ukuran objek serial dan jumlah memori yang dikonsumsi saat hidup.
sumber
Pertama "ukuran objek" bukan konsep yang didefinisikan dengan baik di Jawa. Anda dapat memaksudkan objek itu sendiri, hanya dengan anggota-anggotanya, Obyek dan semua objek yang dirujuknya (grafik referensi). Anda bisa mengartikan ukuran dalam memori atau ukuran pada disk. Dan JVM diizinkan untuk mengoptimalkan hal-hal seperti Strings.
Jadi satu-satunya cara yang benar adalah bertanya pada JVM, dengan profiler yang bagus (saya menggunakan YourKit ), yang mungkin bukan yang Anda inginkan.
Namun, dari uraian di atas sepertinya setiap baris akan mandiri, dan tidak memiliki pohon dependensi yang besar, sehingga metode serialisasi mungkin akan menjadi pendekatan yang baik pada sebagian besar JVM. Cara termudah untuk melakukan ini adalah sebagai berikut:
Ingat bahwa jika Anda memiliki objek dengan referensi umum, ini tidak akan memberikan hasil yang benar, dan ukuran serialisasi tidak akan selalu cocok dengan ukuran dalam memori, tetapi merupakan perkiraan yang baik. Kode akan sedikit lebih efisien jika Anda menginisialisasi ukuran ByteArrayOutputStream ke nilai yang masuk akal.
sumber
Jika Anda hanya ingin tahu berapa banyak memori yang digunakan dalam JVM Anda, dan berapa banyak yang gratis, Anda dapat mencoba sesuatu seperti ini:
sunting: Saya pikir ini mungkin membantu karena penulis pertanyaan juga menyatakan dia ingin memiliki logika yang menangani "baca sebanyak mungkin baris sampai saya menggunakan memori 32MB."
sumber
Kembali ketika saya bekerja di Twitter, saya menulis sebuah utilitas untuk menghitung ukuran objek yang dalam. Ini memperhitungkan model memori yang berbeda (32-bit, oops terkompresi, 64-bit), padding, subclass padding, berfungsi dengan benar pada struktur data array dan array. Anda bisa mengkompilasi file .java yang satu ini; tidak memiliki dependensi eksternal:
https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/objectsize/ObjectSizeCalculator.java
sumber
Sebagian besar jawaban lain memberikan ukuran yang dangkal - misalnya ukuran HashMap tanpa kunci atau nilai apa pun, yang sepertinya tidak sesuai dengan yang Anda inginkan.
Proyek jamm menggunakan paket java.lang.instrumentation di atas tetapi berjalan pohon dan sehingga dapat memberi Anda penggunaan memori yang mendalam.
https://github.com/jbellis/jamm
sumber
Anda harus berjalan di objek menggunakan refleksi. Hati-hati seperti yang Anda lakukan:
byte
secara teoritis 1 byte tidak berarti hanya membutuhkan satu memori.HashMap
atau kira - kira menggunakan objek-sama sebagai pembanding untuk menghilangkan loop tak terbatas.@jodonnell: Saya suka kesederhanaan solusi Anda, tetapi banyak objek tidak Serializable (jadi ini akan melempar pengecualian), bidang dapat bersifat sementara, dan objek dapat menimpa metode standar.
sumber
Anda harus mengukurnya dengan alat, atau memperkirakannya dengan tangan, dan itu tergantung pada JVM yang Anda gunakan.
Ada beberapa overhead tetap per objek. Ini spesifik JVM, tapi saya biasanya memperkirakan 40 byte. Maka Anda harus melihat anggota kelas. Referensi objek adalah 4 (8) byte dalam JVM 32-bit (64-bit). Jenis-jenis primitif adalah:
Array mengikuti aturan yang sama; artinya, ini adalah referensi objek sehingga membutuhkan 4 (atau 8) byte di objek Anda, dan kemudian panjangnya dikalikan dengan ukuran elemennya.
Mencoba melakukannya secara terprogram dengan panggilan
Runtime.freeMemory()
saja tidak memberikan Anda banyak akurasi, karena panggilan tidak sinkron ke pengumpul sampah, dll. Membuat profil tumpukan dengan -Xrunhprof atau alat lain akan memberi Anda hasil yang paling akurat.sumber
boolean[]
. Sebenarnya semua tipe primitif non double / panjang adalah 4 byte. Yang terakhir adalah 8 (jawabannya salah menempatkan mereka sebagai 4 juga)The
java.lang.instrument.Instrumentation
kelas menyediakan cara yang bagus untuk mendapatkan ukuran Obyek Jawa, tetapi mengharuskan Anda untuk menentukanpremain
dan menjalankan program Anda dengan agen java. Ini sangat membosankan ketika Anda tidak membutuhkan agen apa pun dan kemudian Anda harus menyediakan agen Jar palsu untuk aplikasi Anda.Jadi saya mendapat solusi alternatif menggunakan
Unsafe
kelas darisun.misc
. Jadi, dengan mempertimbangkan penumpukan objek tumpukan sesuai dengan arsitektur prosesor dan menghitung bidang offset maksimum, Anda dapat mengukur ukuran Obyek Java. Dalam contoh di bawah ini saya menggunakan kelas bantuUtilUnsafe
untuk mendapatkan referensi kesun.misc.Unsafe
objek.sumber
Ada juga alat Pengukur Memori (sebelumnya di Google Code , sekarang di GitHub ), yang sederhana dan diterbitkan di bawah lisensi Apache 2.0 yang ramah komersial , seperti yang dibahas dalam pertanyaan serupa .
Ini juga membutuhkan argumen baris perintah ke penerjemah java jika Anda ingin mengukur konsumsi byte memori, tetapi sebaliknya berfungsi dengan baik, setidaknya dalam skenario saya telah menggunakannya.
sumber
Tanpa harus mengacaukan instrumentasi dan sebagainya, dan jika Anda tidak perlu mengetahui ukuran byte-tepat dari suatu objek, Anda bisa menggunakan pendekatan berikut:
Dengan cara ini Anda membaca memori yang digunakan sebelum dan sesudah, dan memanggil GC sebelum mendapatkan memori yang digunakan Anda menurunkan "noise" hampir ke 0.
Untuk hasil yang lebih andal, Anda dapat menjalankan pekerjaan Anda n kali, dan kemudian membagi memori yang digunakan dengan n, memperoleh berapa banyak memori yang dibutuhkan oleh satu kali menjalankan. Bahkan lebih, Anda dapat menjalankan semuanya lebih banyak kali dan menghasilkan rata-rata.
sumber
System.gc()
hanya memberitahukan bahwa Anda ingin GC? Tidak dijamin bahwa GC disebut sama sekali.Berikut adalah utilitas yang saya buat menggunakan beberapa contoh terkait untuk menangani 32-bit, 64-bit dan 64-bit dengan OOP terkompresi. Itu menggunakan
sun.misc.Unsafe
.Ini digunakan
Unsafe.addressSize()
untuk mendapatkan ukuran pointer asli danUnsafe.arrayIndexScale( Object[].class )
untuk ukuran referensi Java.Ia menggunakan bidang offset dari kelas yang dikenal untuk menghitung ukuran dasar suatu objek.
sumber
Instrumentation
karena saya tidak memulai kucing jantan,ObjectSizeCalculator
karena tidak yakin jenis VM (HotSpot) danJOL
bacouse spring bean. Saya menggunakan ini dan menambahkan parameter kedua untuk mengabaikan singleton yaituAbstractRefreshableApplicationContext.getBeanFactory().getSingletonMutex()
daninternalSizeOf
kode refactor untuk mengabaikan Kelas dan EnumSaya mencari perhitungan runtime ukuran objek yang memenuhi persyaratan berikut:
Berikut ini didasarkan pada kode inti dari artikel spesialis java asli ( https://www.javaspecialists.eu/archive/Issue078.html ) dan beberapa bit dari versi Tidak Aman dalam jawaban lain untuk pertanyaan ini.
Saya harap seseorang menemukannya bermanfaat.
}
sumber
Tidak ada panggilan metode, jika itu yang Anda minta. Dengan sedikit riset, saya kira Anda bisa menulis sendiri. Sebuah instance tertentu memiliki ukuran tetap yang berasal dari jumlah referensi dan nilai-nilai primitif ditambah data pembukuan instance. Anda cukup berjalan grafik objek. Semakin sedikit variasi jenis baris, semakin mudah.
Jika itu terlalu lambat atau hanya lebih banyak masalah daripada nilainya, selalu ada aturan kuno yang baik.
sumber
Saya menulis tes cepat sekali untuk memperkirakan dengan cepat:
Konsep umum adalah mengalokasikan objek dan mengukur perubahan di ruang tumpukan gratis. Kuncinya adalah
getFreeMemory()
, yang meminta GC berjalan dan menunggu ukuran tumpukan gratis yang dilaporkan untuk stabil . Output di atas adalah:Itulah yang kami harapkan, memberikan perilaku penyelarasan dan kemungkinan tumpukan header blok.
Metode instrumentasi yang dirinci dalam jawaban yang diterima di sini adalah yang paling akurat. Metode yang saya jelaskan ini akurat tetapi hanya dalam kondisi yang terkendali di mana tidak ada utas lain yang membuat / membuang objek.
sumber
Cukup gunakan java visual VM.
Ini memiliki semua yang Anda butuhkan untuk profil dan men-debug masalah memori.
Ini juga memiliki konsol OQL (Object Query Language) yang memungkinkan Anda untuk melakukan banyak hal berguna, salah satunya adalah
sizeof(o)
sumber
Saat menggunakan JetBrains IntelliJ, pertama-tama aktifkan "Lampirkan agen memori" di File | Pengaturan | Bangun, Eksekusi, Penempatan | Debugger.
Saat debugging, klik kanan variabel yang diinginkan dan pilih "Hitung Ukuran yang Ditahan":
sumber
Jawaban saya didasarkan pada kode yang diberikan oleh Nick. Kode itu mengukur jumlah total byte yang ditempati oleh objek berseri. Jadi ini sebenarnya mengukur hal-hal serialisasi + jejak memori objek polos (hanya cerita bersambung misalnya
int
dan Anda akan melihat bahwa jumlah total byte serial tidak4
). Jadi jika Anda ingin mendapatkan angka byte mentah yang digunakan tepat untuk objek Anda - Anda perlu sedikit memodifikasi kode itu. Seperti itu:Saya sudah menguji solusi ini dengan tipe primitif, String, dan pada beberapa kelas sepele. Mungkin tidak ada kasus tertutup juga.
UPDATE: Contoh dimodifikasi untuk mendukung perhitungan jejak memori objek array.
sumber
Anda bisa menghasilkan heap dump (dengan jmap, misalnya) dan kemudian menganalisis output untuk menemukan ukuran objek. Ini adalah solusi offline, tetapi Anda dapat memeriksa ukuran yang dangkal dan dalam, dll.
sumber
ukuran memberi Anda peningkatan penggunaan memori jvm karena pembuatan objek dan yang biasanya adalah ukuran objek.
sumber
Jawaban ini tidak terkait dengan ukuran objek, tetapi ketika Anda menggunakan array untuk mengakomodasi objek; berapa ukuran memori yang akan dialokasikan untuk objek.
Jadi array, daftar, atau petakan semua koleksi tidak akan benar-benar menyimpan objek (hanya pada saat primitif, ukuran memori objek nyata diperlukan), ia hanya akan menyimpan referensi untuk objek-objek tersebut.
Sekarang
Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection
PRIMITIF
BENDA
Maksud saya mengatakan semua objek REFERENSI hanya membutuhkan 4 byte memori. Mungkin referensi String ATAU referensi objek ganda, tetapi tergantung pada pembuatan objek memori yang dibutuhkan akan bervariasi.
misalnya) Jika saya membuat objek untuk kelas di bawah ini
ReferenceMemoryTest
maka 4 + 4 + 4 = 12 byte memori akan dibuat. Memori mungkin berbeda ketika Anda mencoba untuk menginisialisasi referensi.Jadi ketika membuat objek / referensi array, semua isinya akan ditempati dengan referensi NULL. Dan kita tahu setiap referensi membutuhkan 4 byte.
Dan akhirnya, alokasi memori untuk kode di bawah ini adalah 20 byte.
ReferenceMemoryTest ref1 = new ReferenceMemoryTest (); (4 (ref1) + 12 = 16 byte) ReferenceMemoryTest ref2 = ref1; (4 (ref2) + 16 = 20 byte)
sumber
Misalkan saya mendeklarasikan kelas yang bernama
Complex
seperti:Untuk melihat berapa banyak memori yang dialokasikan untuk contoh langsung dari kelas ini:
sumber
Untuk JSONObject, kode di bawah ini dapat membantu Anda.
mengembalikan ukuran dalam byte
Saya memeriksanya dengan objek JSONArray saya dengan menulisnya ke file. Ini memberi ukuran objek.
sumber
Saya ragu Anda ingin melakukannya secara terprogram kecuali Anda hanya ingin melakukannya sekali dan menyimpannya untuk digunakan di masa depan. Itu hal yang mahal untuk dilakukan. Tidak ada sizeof () operator di Jawa, dan bahkan jika ada, itu hanya akan menghitung biaya referensi ke objek lain dan ukuran primitif.
Salah satu cara Anda bisa melakukannya adalah dengan membuat serial hal itu ke File dan melihat ukuran file, seperti ini:
Tentu saja, ini mengasumsikan bahwa setiap objek berbeda dan tidak mengandung referensi non-transien untuk hal lain.
Strategi lain adalah mengambil setiap objek dan memeriksa anggotanya dengan refleksi dan menjumlahkan ukurannya (boolean & byte = 1 byte, pendek & char = 2 byte, dll.), Dengan menelusuri hierarki keanggotaan. Tapi itu membosankan dan mahal dan akhirnya melakukan hal yang sama dengan strategi serialisasi.
sumber
java.lang.Integer
menghasilkan sekitar 80 byte, di mana representasi heap biasanya 32 (tidak seperti representasi aliran objek, representasi heap tergantung pada ukuran pointer dan penyelarasan objek). Sebaliknya,null
referensi serial membutuhkan satu byte, bukan empat atau delapan byte di memori tumpukan.