Untuk sembarang contoh (kumpulan objek, komposisi, objek tunggal, dll yang berbeda)
Bagaimana cara menentukan ukurannya dalam byte?
(Saat ini saya memiliki koleksi berbagai objek dan saya mencoba menentukan ukuran agregatnya)
EDIT: Apakah seseorang telah menulis metode ekstensi untuk Object yang dapat melakukan ini? Itu akan sangat bagus.
Jawaban:
Pertama-tama, peringatan: yang berikut ini benar-benar berada di ranah peretasan yang buruk dan tidak berdokumen. Jangan mengandalkan cara ini berfungsi - bahkan jika berfungsi untuk Anda sekarang, ini mungkin berhenti berfungsi besok, dengan pembaruan .NET kecil atau besar.
Anda dapat menggunakan informasi dalam artikel ini tentang internal CLR Majalah MSDN Edisi 2005 Mei - Telusuri Internal .NET Framework untuk Melihat Bagaimana CLR Membuat Objek Waktu Proses - terakhir saya periksa, itu masih berlaku. Berikut adalah cara melakukannya (mengambil bidang internal "Ukuran Instans Dasar" melalui
TypeHandle
tipe).Ini bekerja pada 3.5 SP1 32-bit. Saya tidak yakin apakah ukuran bidang sama pada 64-bit - Anda mungkin harus menyesuaikan jenis dan / atau offset jika tidak.
Ini akan bekerja untuk semua jenis "normal", yang semua instansinya memiliki jenis yang sama dan terdefinisi dengan baik. Yang tidak benar ini adalah array dan string, dan saya percaya juga
StringBuilder
. Untuk mereka, Anda harus menambahkan ukuran semua elemen yang dimuat ke ukuran instance dasarnya.sumber
Cannot take the address of, get the size of, or declare a pointer to a managed type ('System.RuntimeTypeHandle')
Marshal.ReadInt32(type.TypeHandle.Value, 4)
berfungsi untuk x86 dan x64. Saya hanya menguji tipe struct dan kelas. Ingatlah bahwa ini mengembalikan ukuran kotak untuk tipe nilai. @Pavel Mungkin Anda bisa memperbarui jawaban Anda.type
denganobj.GetType()
contoh nya. Tidak masalah kerangka kerja mana yang Anda gunakan, hanya CLR (v2 atau v4 atau CoreCLR) apa. Saya belum mencoba ini di CoreCLR.Anda mungkin dapat memperkirakan ukuran dengan berpura-pura menserialisasinya dengan serializer biner (tetapi merutekan keluaran ke terlupakan) jika Anda bekerja dengan objek yang dapat diserialkan.
sumber
Untuk tipe tidak terkelola alias tipe nilai, struct:
Untuk objek yang dikelola, semakin dekat saya adalah sebuah pendekatan.
Jangan gunakan serialisasi. Pemformat biner menambahkan header, sehingga Anda dapat mengubah kelas dan memuat file berseri lama ke dalam kelas yang dimodifikasi.
Juga tidak akan memberi tahu Anda ukuran sebenarnya dalam memori juga tidak akan memperhitungkan keselarasan memori akun.
[Sunting] Dengan menggunakan BiteConverter.GetBytes (prop-value) secara rekursif pada setiap properti kelas Anda, Anda akan mendapatkan konten dalam byte, yang tidak menghitung bobot kelas atau referensi tetapi lebih mendekati kenyataan. Saya akan merekomendasikan untuk menggunakan array byte untuk data dan kelas proxy yang tidak terkelola untuk mengakses nilai menggunakan pengecoran penunjuk jika ukuran penting, perhatikan bahwa itu akan menjadi memori non-aligned sehingga pada komputer lama akan lambat tetapi dataset BESAR pada RAM MODERN akan menjadi jauh lebih cepat, karena meminimalkan ukuran untuk membaca dari RAM akan berdampak lebih besar daripada tidak selaras.
sumber
Ini tidak berlaku untuk implementasi .NET saat ini, tetapi satu hal yang perlu diingat dengan runtime yang dikumpulkan / dikelola sampah adalah ukuran yang dialokasikan dari suatu objek dapat berubah sepanjang masa program. Misalnya, beberapa pengumpul sampah generasi (seperti pengumpul Hibrid Penghitungan Referensi Generasi / Tersembunyi ) hanya perlu menyimpan informasi tertentu setelah suatu objek dipindahkan dari pembibitan ke ruang dewasa.
Ini membuatnya tidak mungkin untuk membuat API generik yang andal untuk mengekspos ukuran objek.
sumber
solusi aman dengan beberapa pengoptimalan kode CyberSaving / MemoryUsage . beberapa kasus:
Ia bekerja juga dengan kelas:
sumber
Ini tidak mungkin dilakukan saat runtime.
Ada berbagai profiler memori yang menampilkan ukuran objek.
EDIT : Anda dapat menulis program kedua yang membuat profil yang pertama menggunakan API Profil CLR dan berkomunikasi dengannya melalui remote atau sesuatu.
sumber
Gunakan Son Of Strike yang memiliki perintah
ObjSize
.Perhatikan bahwa memori aktual yang dikonsumsi selalu lebih besar daripada
ObjSize
laporan karena ada laporansynkblk
yang berada tepat sebelum data objek.Baca lebih lanjut tentang keduanya di sini Majalah MSDN Edisi 2005 Mei - Bor Ke Internal .NET Framework untuk Melihat Bagaimana CLR Membuat Objek Runtime .
sumber
AFAIK, Anda tidak bisa, tanpa benar-benar menghitung secara mendalam ukuran setiap anggota dalam byte. Tetapi sekali lagi, apakah ukuran anggota (seperti elemen di dalam koleksi) diperhitungkan terhadap ukuran objek, atau penunjuk ke anggota tersebut diperhitungkan terhadap ukuran objek? Tergantung bagaimana Anda mendefinisikannya.
Saya telah mengalami situasi ini sebelumnya di mana saya ingin membatasi objek di cache saya berdasarkan memori yang mereka konsumsi.
Nah, jika ada trik untuk melakukan itu, saya akan senang mengetahuinya!
sumber
Untuk tipe nilai, Anda bisa menggunakan
Marshal.SizeOf
. Tentu saja, ia mengembalikan jumlah byte yang diperlukan untuk menyusun struktur dalam memori yang tidak dikelola, yang belum tentu digunakan oleh CLR.sumber
Anda dapat menggunakan refleksi untuk mengumpulkan semua anggota publik atau informasi properti (berdasarkan tipe objek). Tidak ada cara untuk menentukan ukuran tanpa menelusuri setiap bagian data pada objek.
sumber
Untuk siapa pun yang mencari solusi yang tidak memerlukan
[Serializable]
kelas dan hasilnya adalah perkiraan, bukan ilmu pasti. Metode terbaik yang bisa saya temukan adalah serialisasi json ke dalam aliran memori menggunakan pengkodean UTF32.Tidak, ini tidak akan memberi Anda ukuran pasti yang akan digunakan dalam memori. Seperti yang disebutkan sebelumnya, itu tidak mungkin. Tapi itu akan memberi Anda perkiraan kasar.
Perhatikan bahwa ini juga sangat lambat.
sumber
Dari Pavel dan jnm2:
Di samping catatan hati-hati karena hanya bekerja dengan objek memori yang berdekatan
sumber
Saya telah membuat tes benchmark untuk berbagai koleksi di .NET: https://github.com/scholtz/TestDotNetCollectionsMemoryAllocation
Hasilnya adalah sebagai berikut untuk .NET Core 2.2 dengan 1.000.000 objek dengan 3 properti dialokasikan:
Untuk tes memori saya menemukan yang terbaik untuk digunakan
sumber
Untuk array struct / nilai, saya memiliki hasil yang berbeda dengan:
(contoh yang terlalu disederhanakan)
Apa pun pendekatannya, Anda benar-benar perlu memahami cara kerja .Net untuk menafsirkan hasil dengan benar. Misalnya, ukuran elemen yang dikembalikan adalah ukuran elemen "selaras", dengan beberapa padding. Overhead dan ukurannya berbeda-beda bergantung pada penggunaan tipe: "boxed" pada GC heap, di stack, sebagai field, sebagai elemen array.
(Saya ingin tahu apa yang akan menjadi dampak memori menggunakan struct kosong "dummy" (tanpa bidang apa pun) untuk meniru argumen "opsional" generik; membuat tes dengan tata letak berbeda yang melibatkan struct kosong, saya dapat melihat bahwa struct kosong menggunakan ( setidaknya) 1 byte per elemen; saya samar-samar ingat itu karena .Net membutuhkan alamat yang berbeda untuk setiap bidang, yang tidak akan berfungsi jika bidang benar-benar kosong / berukuran 0).
sumber
Cara paling sederhana adalah:
int size = *((int*)type.TypeHandle.Value + 1)
Saya tahu ini adalah detail implementasi tetapi GC mengandalkannya dan itu harus sedekat mungkin dengan tabel metodologi untuk efisiensi plus mempertimbangkan bagaimana kompleks kode GC tidak ada yang berani mengubahnya di masa mendatang. Sebenarnya ini berfungsi untuk setiap versi minor / mayor dari .net framework + .net core. (Saat ini tidak dapat menguji 1.0)
Jika Anda ingin cara yang lebih andal, keluarkan struct dalam rakitan dinamis dengan
[StructLayout(LayoutKind.Auto)]
bidang yang sama persis dalam urutan yang sama, ambil ukurannya dengan Tetapi jika kelas Anda berasal dari kelas lain, Anda perlu menemukan setiap ukuran dari kelas dasar secara terpisah dan tambahkan + 2 * Inptr.Size lagi untuk header. Anda dapat melakukan ini dengan mendapatkan bidang dengan bendera. sizeof instruksi IL. Anda mungkin ingin mengeluarkan metode statis dalam struct yang hanya mengembalikan nilai ini. Kemudian tambahkan 2 * IntPtr.Size untuk header objek. Ini akan memberi Anda nilai yang tepat.BindingFlags.DeclaredOnly
Array dan string hanya menambahkan ukuran itu panjang * ukuran elemennya. Untuk ukuran kumulatif objek aggreagate Anda perlu menerapkan solusi yang lebih canggih yang melibatkan mengunjungi setiap bidang dan memeriksa isinya.
sumber