.NET adalah runtime yang dikelola . Ini berarti bahwa itu berisi fungsi tingkat tinggi yang mengontrol program Anda untuk Anda (dari Pendahuluan hingga Common Language Runtime (CLR), 2007 ):
Runtime menyediakan banyak fungsi, jadi mudah untuk membaginya ke dalam kategori berikut:
- Fungsi utama yang memengaruhi perangkat orang lain. Ini termasuk:
- pengumpulan sampah;
- mengamankan akses memori dan mengetikkan keamanan sistem;
- dukungan tingkat tinggi untuk bahasa pemrograman.
- Fungsi tambahan - bekerja berdasarkan yang utama. Banyak program bermanfaat yang melakukannya tanpa mereka. Fungsi-fungsi ini meliputi:
- Mengisolasi aplikasi menggunakan AppDomains
- perlindungan aplikasi dan isolasi kotak pasir.
- Fungsi lain dibutuhkan oleh semua runtime, tetapi mereka tidak menggunakan fungsi CLR dasar. Fitur-fitur tersebut mencerminkan keinginan untuk menciptakan lingkungan pemrograman yang lengkap. Ini termasuk:
- kontrol versi;
- debugging / profil;
- memastikan interaksi.
Dapat dilihat bahwa meskipun debugging dan profiling bukan fungsi utama atau tambahan, mereka ada dalam daftar karena ' keinginan untuk menciptakan lingkungan pemrograman yang lengkap '.

Sisa postingan ini menjelaskan fitur pemantauan , pengamatan, dan introspeksi apa yang ada dalam Core CLR, mengapa mereka berguna, dan bagaimana lingkungan menyediakannya.
Diagnostik
Pertama, lihat informasi diagnostik yang diberikan CLR kepada kami. Secara tradisional, Pelacakan Peristiwa untuk Windows (ETW) telah digunakan untuk ini.
Ada banyak peristiwa dimana CLR memberikan informasi. Mereka terkait dengan:
- pengumpulan sampah (GC);
- Kompilasi JIT;
- modul dan domain aplikasi;
- bekerja dengan utas dan konflik saat memblokir;
- serta banyak lainnya.
Misalnya, di sini suatu peristiwa terjadi selama pemuatan di AppDomain , di sini acara tersebut dikaitkan dengan melempar pengecualian , dan di sini dengan siklus alokasi memori oleh pengumpul sampah .
Tampilan perf
Jika Anda ingin melihat peristiwa dalam sistem jejak (ETW) yang terkait dengan aplikasi .NET Anda, saya sarankan menggunakan alat PerfView yang sangat baik dan mulai dengan video pelatihan ini atau presentasi PerfView: Alat Kinerja .NET Ultimate ini . PerfView telah dikenal luas karena menyediakan informasi yang tak ternilai. Sebagai contoh, insinyur Microsoft secara teratur menggunakannya untuk menganalisis kinerja .
Infrastruktur umum
Jika tiba-tiba namanya tidak jelas, pelacakan acara di ETW hanya tersedia di bawah Windows, yang tidak cocok dengan dunia lintas-platform .NET Core. Anda dapat menggunakan PerfView untuk menganalisis kinerja di Linux (menggunakan LTTng). Namun, alat baris perintah ini, yang disebut PerfCollect, hanya mengumpulkan data. Kemampuan analisis dan antarmuka pengguna yang kaya (termasuk flamegraphs ) saat ini hanya tersedia dalam solusi Windows.
Tetapi jika Anda masih ingin menganalisis kinerja .NET di Linux, ada beberapa pendekatan lain:
Tautan kedua di atas mengarah ke diskusi tentang infrastruktur EventPipe baru, yang sedang dikerjakan di .NET Core (di samping EventSources & EventListeners). Tujuan pengembangannya dapat ditemukan dalam dokumen Desain Pemantauan Kinerja Cross-Platform . Pada tingkat tinggi, infrastruktur ini akan menciptakan satu tempat di mana CLR akan mengirim acara yang berkaitan dengan diagnostik dan kinerja. Kemudian acara-acara ini akan dialihkan ke satu atau lebih penebang, yang, misalnya, dapat mencakup ETW, LTTng dan BPF. Logger yang diperlukan akan ditentukan tergantung pada OS atau platform di mana CLR berjalan. Untuk penjelasan rinci tentang pro dan kontra dari berbagai teknologi logging, lihat .NET Cross-Plat Performance dan Eventing Design .
Kemajuan EventPipes dipantau melalui proyek Pemantauan Kinerja dan Masalah 'EventPipe' terkait.
Rencana masa depan
Akhirnya, ada rencana untuk membuat Pengontrol Profil Kinerja , yang memiliki tugas-tugas berikut:
Pengontrol harus mengelola infrastruktur profil dan menyajikan data kinerja yang dihasilkan oleh .NET komponen yang bertanggung jawab untuk diagnostik kinerja secara sederhana dan lintas platform.
Menurut rencana, pengontrol harus menyediakan fungsionalitas berikut melalui server HTTP , menerima semua data yang diperlukan dari infrastruktur EventPipes:
API REST
- Prinsip 1: profil sederhana: profil runtime selama periode waktu X dan kembalikan jejaknya.
- Prinsip 1: profil lanjutan: mulai pelacakan (bersama dengan konfigurasi)
- Prinsip 1: profil lanjutan: pelacakan lengkap (jawaban untuk panggilan ini akan menjadi jejaknya sendiri).
- Prinsip 2: Dapatkan statistik yang terkait dengan semua EventCounters atau EventCounter tertentu.
Halaman HTML yang Dapat Ditelusuri
- Prinsip 1: Representasi tekstual dari semua tumpukan kode yang dikelola dalam suatu proses.
- Membuat snapshot dari proses yang berjalan untuk digunakan sebagai laporan diagnostik sederhana.
- Prinsip 2: menampilkan keadaan saat ini (mungkin dengan riwayat) penghitung EventCounters.
- Memberikan ikhtisar tentang penghitung yang ada dan nilainya.
- MASALAH YANG TAK TERLIBAT: Saya tidak berpikir ada API publik yang diperlukan untuk menghitung EventCounters.
Saya benar-benar ingin melihat apa yang terjadi dengan pengontrol profil kinerja (PPC?). Saya pikir jika itu dibangun ke dalam CLR, itu akan membawa banyak manfaat untuk .NET. Fungsionalitas tersebut ada di runtimes lain .
Pembuatan profil
Alat efektif lain yang dimiliki CLR adalah API profiling. Ini (terutama) digunakan oleh alat pihak ketiga untuk terhubung ke runtime di tingkat rendah. Anda dapat mempelajari lebih lanjut tentang API dari ulasan ini , tetapi pada tingkat tinggi, Anda dapat menggunakannya untuk membuat panggilan balik yang diaktifkan jika:
- acara yang berkaitan dengan pemulung;
- pengecualian dilemparkan;
- majelis dimuat / dibongkar;
- dan masih banyak lagi .
Gambar dari Halaman API Profiling BOTR - Tinjauan Umum
Selain itu, ia memiliki fitur-fitur efektif lainnya. Pertama, Anda dapat mengatur penangan yang dipanggil setiap kali metode .NET dijalankan, baik di lingkungan itu sendiri atau dari kode pengguna. Callback ini dikenal sebagai Enter / Leave handler. Ini adalah contoh yang bagus tentang bagaimana menggunakannya. Namun, untuk ini, Anda perlu memahami konvensi pemanggilan untuk arsitektur OS dan CPU yang berbeda , yang tidak selalu mudah . Juga, ingat bahwa API profil adalah komponen COM yang hanya dapat diakses dari kode C / C ++, tetapi bukan dari C # / F # / VB.NET.
Kedua, profiler dapat menulis ulang kode IL dari setiap metode .NET sebelum kompilasi JIT menggunakan API SetILFunctionBody () . API ini sangat efisien. Ini mendasari banyak alat APM .NET . Anda dapat mempelajari lebih lanjut tentang penggunaannya dari posting saya Cara mengejek kelas yang disegel dan metode statis dan kode terkait.
API ICorProfiler
Ternyata API pembuatan profil berhasil, harus ada segala macam trik di lingkungan runtime. Lihat saja diskusi pada halaman Izinkan izin pada lampiran (lihat ReJIT: Panduan Cara Untuk informasi lebih lanjut tentang ReJIT).
Definisi lengkap semua profil API dan panggilan balik profil dapat ditemukan di \ vm \ inc \ corprof.idl (lihat Bahasa deskripsi antarmuka ). Ini dibagi menjadi 2 bagian logis. Satu bagian adalah profiler -> antarmuka Runtime Environment (EE) , yang dikenal sebagai ICorProfilerInfo
:
// , ICorProfilerInfo*, // . , DLL // , // .
Ini diimplementasikan dalam file-file berikut:
Bagian utama lainnya adalah callback Runtime -> Profiler, yang dikelompokkan di bawah antarmuka ICorProfilerCallback
:
// // ICorProfilerCallaback* . // , EEToProfInterfaceImpl.
Callback ini diimplementasikan dalam file-file berikut:
Akhirnya, perlu dicatat bahwa profil API tidak dapat berfungsi pada semua OS dan arsitektur yang menjalankan .NET Core. Berikut ini salah satu contohnya: Masalah rintisan panggilan ELT di Linux . Lihat Status API Profiler CoreCLR untuk informasi lebih lanjut.
Pembuatan profil v. Debugging
Sebagai penyimpangan kecil, saya harus mengatakan bahwa profil dan debugging masih tumpang tindih sedikit. Oleh karena itu, penting untuk memahami apa yang disediakan oleh API berbeda dalam konteks .NET Runtime (diambil dari CLR Debugging vs. CLR Profiling ).
Perbedaan antara debugging dan profil di CLR
Debugging
Pengembang berbeda memahami apa itu debugging. Sebagai contoh, saya bertanya di Twitter โbagaimana Anda men-debug program .NETโ dan mendapat banyak jawaban berbeda . Pada saat yang sama, jawabannya memang berisi daftar alat dan metode yang bagus, jadi saya sarankan untuk melihatnya. Terima kasih #LazyWeb
Saya pikir yang terbaik dari semua esensi dari debugging mencerminkan pesan ini:
CLR menyediakan daftar lengkap fitur-fitur terkait debugging. Namun, mengapa dana ini dibutuhkan? Setidaknya ada tiga alasan yang disebutkan dalam postingan hebat ini. Mengapa debugging yang dikelola berbeda dengan debugging asli? :
- Debugging kode yang tidak dikelola dapat diabstraksi pada level perangkat keras, tetapi debugging kode yang dikelola harus diabstraksikan pada level IL-code.
- Kode terkelola debugging membutuhkan banyak informasi yang tidak tersedia sebelum eksekusi.
- Debugger kode yang dikelola harus berkoordinasi dengan pengumpul sampah (GC)
Oleh karena itu, untuk kemudahan penggunaan, CLR harus menyediakan API debugging tingkat tinggi yang dikenal sebagai ICorDebug
. Itu ditunjukkan pada gambar di bawah ini yang menunjukkan skenario debugging umum (sumber: BOTR):
API ICorDebug
Prinsip implementasi dan deskripsi berbagai komponen diambil dari CLR Debugging, sebuah pengantar singkat :
Semua dukungan debugging di .Net diimplementasikan di atas perpustakaan dll, yang kita sebut The Dac. File ini (biasanya disebut mscordacwks.dll
) adalah elemen struktural untuk API debugging publik kami ( ICorDebug
) dan dua API debugging pribadi: SOS-Dac API dan IXCLR.
Di dunia yang ideal, semua orang akan menggunakan ICorDebug
, API publik kami. Namun, ICorDebug
tidak memiliki banyak fitur yang dibutuhkan pengembang alat. Ini adalah masalah yang kami coba perbaiki di mana kami bisa. Namun, peningkatan ini hanya ada di CL.v.next, tetapi tidak di versi CLR sebelumnya. Bahkan, dukungan debug dump dump muncul di API ICorDebug
hanya dengan rilis CLR v4. Setiap orang yang menggunakan crash dumps untuk debugging di CLR v2 tidak akan dapat menerapkan ICorDebug
sama sekali.
(Lihat SOS & ICorDebug untuk informasi lebih lanjut)
Faktanya, API ICorDebug
dibagi menjadi lebih dari 70 antarmuka. Saya tidak akan memberikan semuanya, tetapi saya akan menunjukkan berdasarkan kategori apa mereka dapat dibagi. Untuk informasi lebih lanjut, lihat Partisi ICorDebug, di mana daftar ini telah diterbitkan.
- Tingkat atas : ICorDebug + ICorDebug2 - antarmuka tingkat atas yang berfungsi sempurna sebagai kumpulan objek ICorDebugProcess.
- Callback : Kejadian debugging kode terkelola dikirim melalui metode ke objek callback yang diimplementasikan oleh debugger.
- Proses : Set antarmuka ini mewakili kode kerja dan termasuk API yang terkait dengan peristiwa.
- Kode / Jenis Inspeksi : Sebagian besar bekerja dengan gambar PE statis, tetapi ada metode yang mudah untuk data nyata.
- Kontrol pelaksanaan : Kemampuan untuk memantau kemajuan utas. Dalam praktiknya, ini berarti kemampuan untuk mengatur breakpoints (F9) dan melangkah melalui kode (entri kode F11, bypass kode F10, kode keluar S + F11). Fungsi kontrol eksekusi ICorDebug hanya berfungsi dalam kode terkelola.
- Utas + tumpukan panggilan : tumpukan panggilan adalah dasar untuk fungsi inspeksi yang diterapkan oleh debugger. Bekerja dengan tumpukan panggilan dilakukan menggunakan antarmuka berikut. ICorDebug hanya mendukung debugging kode terkelola dan, karenanya, Anda dapat melacak tumpukan kode terkelola saja.
- Pemeriksaan objek : Pemeriksaan objek adalah bagian dari API yang memungkinkan Anda untuk melihat nilai-nilai variabel dalam kode debug. Untuk setiap antarmuka, saya memberikan metode MVP, yang menurut saya, harus menjelaskan secara singkat tujuan dari antarmuka ini.
Seperti halnya profil API, level dukungan API debugging bervariasi menurut OS dan arsitektur prosesor. Misalnya, pada Agustus 2018, masih belum ada solusi ARM Linux untuk mendiagnosis dan men-debug kode yang dikelola. Untuk informasi lebih lanjut tentang dukungan Linux, lihat Debugging .NET Core di Linux dengan LLDB dan repositori Diagnostics dari Microsoft, yang bertujuan untuk mempermudah debugging program .NET di Linux.
Terakhir, jika Anda ingin melihat bagaimana ICorDebug
API terlihat di C #, lihat pembungkus di perpustakaan CLRMD, termasuk semua panggilan balik yang tersedia (lebih banyak tentang CLRMD akan dibahas nanti dalam posting ini).
SOS dan DAC
Komponen Akses Data (DAC) dibahas secara rinci di halaman BOTR . Pada dasarnya, ini menyediakan akses keluar-proses ke struktur data CLR sehingga informasi di dalamnya dapat dibaca dari proses lain. Dengan demikian, debugger (melalui ICorDebug
) atau ekstensi 'Son of Strike' (SOS) dapat mengakses instance CLR yang berjalan atau dump memori dan menemukan, misalnya:
- semua utas berjalan;
- berhasil menumpuk benda
- informasi lengkap tentang metode ini, termasuk kode mesin;
- jejak tumpukan saat ini.
Penyimpangan kecil : jika Anda ingin mencari tahu dari mana nama-nama aneh ini berasal dan mendapatkan sedikit pelajaran dalam sejarah .NET, lihat jawaban ini di Stack Overflow .
Daftar lengkap perintah SOS sangat mengesankan . Jika Anda menggunakannya bersama dengan WinDBG, Anda dapat mengetahui apa yang terjadi di dalam program Anda dan CLR pada tingkat yang sangat rendah. Untuk melihat bagaimana semuanya diimplementasikan, mari kita lihat !HeapStat
, yang menampilkan deskripsi ukuran berbagai tumpukan yang digunakan. NET GC:
(Gambar diambil dari SOS: Rilis yang akan datang memiliki beberapa perintah baru - HeapStat)
Berikut ini adalah aliran kode yang menunjukkan bagaimana SOS dan DAC bekerja bersama:
- Tim SOS Lengkap
!HeapStat
( tautan ) - Kode SOS di perintah
!HeapStat
yang berfungsi dengan Workstation GC (tautan) - SOS Function
GCHeapUsageStats(..)
, yang melakukan bagian pekerjaan yang paling sulit ( tautan ) - Shared
DacpGcHeapDetails
data yang berisi pointer ke data utama di heap GC, seperti segmen, bit mask, dan generasi individu ( referensi ). - Fungsi DAC
GetGCHeapStaticData
yang mengisi struktur DacpGcHeapDetails
( tautan ) DacpHeapSegmentData
data DacpHeapSegmentData
bersama yang berisi informasi tentang segmen heap GC individu ( tautan )- DAC
GetHeapSegmentData(..)
, yang mengisi struktur DacpHeapSegmentData
( tautan )
Debuggers pihak ketiga
Sejak Microsoft menerbitkan API debugging, pengembang pihak ketiga dapat menggunakan antarmuka ICorDebug
. Berikut adalah daftar yang berhasil saya temukan:
Kesedihan memori
Hal terakhir yang akan kita bicarakan adalah dump memori, yang dapat diperoleh dari sistem kerja dan dianalisis di luarnya. NET runtime selalu mendukung dumping memori di Windows . Dan sekarang. NET Core telah menjadi lintas-platform, alat telah muncul yang melakukan tugas yang sama pada OS lain.
Saat menggunakan dump memori, kadang-kadang sulit untuk mendapatkan versi yang benar, yang cocok dengan file SOS dan DAC. Untungnya, Microsoft baru-baru ini merilis alat CLI dotnet symbol
, yang:
dapat mengunduh semua file yang diperlukan untuk debugging (set karakter, modul, file SOS dan DAC untuk modul coreclr tertentu) untuk setiap dump inti spesifik, minidump atau file platform apa pun yang didukung, termasuk ELF, MachO, Windows DLL, PDB, dan portable PDB
Akhirnya, jika Anda melakukan sedikit analisis dump memori, saya sarankan melihat perpustakaan MD CLR yang sangat baik yang dirilis Microsoft beberapa tahun lalu. Saya sudah menulis tentang fungsinya. Singkatnya, menggunakan perpustakaan, Anda dapat bekerja dengan dump memori melalui C # API yang mengandung kelas intuitif yang menyediakan akses ke ClrHeap, GC Roots, CLR Threads, Stack Frames dan banyak lagi. Faktanya, CLR MD dapat mengimplementasikan sebagian besar (jika tidak semua) perintah SOS.
Anda dapat mengetahui cara kerjanya dari pos ini:
ClrMD Managed Library adalah pembungkus seputar debugging API yang ditujukan untuk penggunaan internal hanya di CLR. Terlepas dari kenyataan bahwa API ini sangat efektif untuk diagnostik, kami tidak mendukung mereka dalam bentuk rilis publik, terdokumentasi, karena penggunaannya kompleks dan terkait erat dengan fitur lain dari implementasi CLR. ClrMD memecahkan masalah ini dengan menyediakan pembungkus yang mudah digunakan dan dikelola di sekitar API debugging tingkat rendah ini.
