Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Artikel ini berlaku untuk: ✔️ .NET Core 3.1 SDK dan versi yang lebih baru
Memori dapat bocor saat aplikasi Anda mereferensikan objek yang tidak lagi perlu melakukan tugas yang diinginkan. Mereferensikan objek ini mencegah pengumpul sampah mendapatkan kembali memori yang digunakan. Itu dapat mengakibatkan penurunan performa dan OutOfMemoryException pengecualian dilemparkan.
Tutorial ini menunjukkan alat untuk menganalisis kebocoran memori di aplikasi .NET menggunakan alat CLI diagnostik .NET. Jika Menggunakan Windows, Anda mungkin dapat menggunakan alat Diagnostik Memori Visual Studio untuk men-debug kebocoran memori.
Tutorial ini menggunakan aplikasi sampel yang sengaja membocorkan memori, sebagai latihan. Anda juga dapat menganalisis aplikasi yang secara tidak sengaja membocorkan memori.
Dalam tutorial ini, Anda akan:
- Periksa penggunaan memori terkelola dengan dotnet-counters.
- Buat file cadangan.
- Analisis penggunaan memori menggunakan file cadangan.
Prasyarat
Tutorial ini menggunakan:
- .NET Core 3.1 SDK atau versi yang lebih baru.
- dotnet-counters untuk memantau penggunaan memori terkelola.
- dotnet-dump untuk mengumpulkan dan menganalisis file cadangan (termasuk ekstensi debugging SOS).
- Contoh aplikasi target debug untuk didiagnosis.
Tutorial mengasumsikan aplikasi dan alat sampel diinstal dan siap digunakan.
Jika aplikasi Anda menjalankan versi .NET yang lebih lama dari .NET 9, antarmuka pengguna output penghitung dotnet akan terlihat sedikit berbeda; lihat penghitung dotnet untuk detailnya.
Memeriksa penggunaan memori terkelola
Sebelum Anda mulai mengumpulkan data diagnostik untuk membantu akar penyebab skenario ini, pastikan Anda benar-benar melihat kebocoran memori (pertumbuhan penggunaan memori). Anda dapat menggunakan alat penghitung dotnet untuk mengonfirmasinya.
Buka jendela konsol dan navigasikan ke direktori tempat Anda mengunduh dan membuka zip target debug sampel. Jalankan target:
dotnet run
Dari konsol terpisah, temukan ID proses:
dotnet-counters ps
Outputnya harus mirip dengan:
4807 DiagnosticScena /home/user/git/samples/core/diagnostics/DiagnosticScenarios/bin/Debug/netcoreapp3.0/DiagnosticScenarios
Nota
Jika perintah sebelumnya tidak berfungsi atau tidak ditemukan, Anda mungkin perlu menginstal alat terlebih dahulu dotnet-counters . Gunakan perintah berikut:
dotnet tool install --global dotnet-counters
Sekarang, periksa penggunaan memori terkelola dengan alat dotnet-counters.
--refresh-interval menentukan jumlah detik antara refresh:
dotnet-counters monitor --refresh-interval 1 -p 4807
Output langsung harus mirip dengan:
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value
[System.Runtime]
dotnet.assembly.count ({assembly}) 111
dotnet.gc.collections ({collection})
gc.heap.generation
------------------
gen0 1
gen1 0
gen2 0
dotnet.gc.heap.total_allocated (By) 4,431,712
dotnet.gc.last_collection.heap.fragmentation.size (By)
gc.heap.generation
------------------
gen0 803,576
gen1 15,456
gen2 0
loh 0
poh 0
dotnet.gc.last_collection.heap.size (By)
gc.heap.generation
------------------
gen0 811,960
gen1 1,214,720
gen2 0
loh 0
poh 24,528
dotnet.gc.last_collection.memory.committed_size (By) 4,296,704
dotnet.gc.pause.time (s) 0.003
dotnet.jit.compilation.time (s) 0.329
dotnet.jit.compiled_il.size (By) 120,212
dotnet.jit.compiled_methods ({method}) 1,202
dotnet.monitor.lock_contentions ({contention}) 2
dotnet.process.cpu.count ({cpu}) 22
dotnet.process.cpu.time (s)
cpu.mode
--------
system 0.344
user 0.344
dotnet.process.memory.working_set (By) 64,331,776
dotnet.thread_pool.queue.length ({work_item}) 0
dotnet.thread_pool.thread.count ({thread}) 0
dotnet.thread_pool.work_item.count ({work_item}) 7
dotnet.timer.count ({timer}) 0
Fokus pada baris ini:
dotnet.gc.last_collection.memory.committed_size (By) 4,296,704
Anda dapat melihat bahwa memori tumpukan terkelola adalah 4 MB tepat setelah startup.
Sekarang, buka URL https://localhost:5001/api/diagscenario/memleak/20000.
Amati bahwa penggunaan memori telah tumbuh menjadi lebih dari 20 MB.
dotnet.gc.last_collection.memory.committed_size (By) 21,020,672
Dengan menonton penggunaan memori, Anda dapat dengan aman mengatakan bahwa memori tumbuh atau bocor. Langkah selanjutnya adalah mengumpulkan data yang tepat untuk analisis memori.
Hasilkan cadangan memori
Saat menganalisis kemungkinan kebocoran memori, Anda memerlukan akses ke tumpuan memori aplikasi untuk menganalisis konten memori. Melihat hubungan antar objek, Anda membuat teori mengapa memori tidak dibebaskan. Sumber data diagnostik umum adalah cadangan memori di Windows atau cadangan inti yang setara di Linux. Untuk menghasilkan cadangan aplikasi .NET, Anda dapat menggunakan alat dotnet-dump .
Gunakan target debug sampel yang sebelumnya dimulai, jalankan perintah berikut untuk menghasilkan core dump Linux:
dotnet-dump collect -p 4807
Hasilnya adalah core dump yang terletak di folder yang sama.
Writing minidump with heap to ./core_20190430_185145
Complete
Nota
Untuk perbandingan dari waktu ke waktu, biarkan proses asli terus berjalan setelah mengumpulkan dump pertama dan kumpulkan dump kedua dengan cara yang sama. Anda kemudian akan memiliki dua dump memori selama periode waktu yang dapat Anda bandingkan dengan melihat tempat di mana penggunaan memori meningkat.
Mulai ulang proses yang gagal
Setelah dump dikumpulkan, Anda harus memiliki informasi yang memadai untuk mendiagnosis proses yang gagal. Jika proses yang gagal berjalan di server produksi, sekarang ini adalah waktu yang ideal untuk remediasi jangka pendek dengan memulai ulang proses.
Dalam tutorial ini, Anda sekarang sudah selesai dengan target Debug Sampel dan Anda dapat menutupnya. Navigasi ke terminal yang memulai server, dan tekan Ctrl+C.
Menganalisis pembuangan inti
Sekarang setelah Anda memiliki core dump yang dihasilkan, gunakan alat dotnet-dump untuk menganalisis dump tersebut.
dotnet-dump analyze core_20190430_185145
Di mana core_20190430_185145 adalah nama core dump yang ingin Anda analisis.
Nota
Jika Anda melihat kesalahan yang menyatakan bahwa libdl.so tidak dapat ditemukan, Anda mungkin harus menginstal paket libc6-dev. Untuk informasi selengkapnya, lihat Prasyarat untuk .NET di Linux.
Anda akan disajikan dengan perintah di mana Anda dapat memasukkan perintah SOS . Umumnya, hal pertama yang ingin Anda lihat adalah keadaan keseluruhan tumpukan terkelola:
> dumpheap -stat
Statistics:
MT Count TotalSize Class Name
...
00007f6c1eeefba8 576 59904 System.Reflection.RuntimeMethodInfo
00007f6c1dc021c8 1749 95696 System.SByte[]
00000000008c9db0 3847 116080 Free
00007f6c1e784a18 175 128640 System.Char[]
00007f6c1dbf5510 217 133504 System.Object[]
00007f6c1dc014c0 467 416464 System.Byte[]
00007f6c21625038 6 4063376 testwebapi.Controllers.Customer[]
00007f6c20a67498 200000 4800000 testwebapi.Controllers.Customer
00007f6c1dc00f90 206770 19494060 System.String
Total 428516 objects
Di sini Anda dapat melihat bahwa sebagian besar objek adalah objek String atau Customer .
Anda dapat menggunakan dumpheap perintah lagi dengan tabel metode (MT) untuk mendapatkan daftar semua String instans:
> dumpheap -mt 00007f6c1dc00f90
Address MT Size
...
00007f6ad09421f8 00007faddaa50f90 94
...
00007f6ad0965b20 00007f6c1dc00f90 80
00007f6ad0965c10 00007f6c1dc00f90 80
00007f6ad0965d00 00007f6c1dc00f90 80
00007f6ad0965df0 00007f6c1dc00f90 80
00007f6ad0965ee0 00007f6c1dc00f90 80
Statistics:
MT Count TotalSize Class Name
00007f6c1dc00f90 206770 19494060 System.String
Total 206770 objects
Anda sekarang dapat menggunakan gcroot perintah pada System.String instans untuk melihat bagaimana dan mengapa objek berakar:
> gcroot 00007f6ad09421f8
Thread 3f68:
00007F6795BB58A0 00007F6C1D7D0745 System.Diagnostics.Tracing.CounterGroup.PollForValues() [/_/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs @ 260]
rbx: (interior)
-> 00007F6BDFFFF038 System.Object[]
-> 00007F69D0033570 testwebapi.Controllers.Processor
-> 00007F69D0033588 testwebapi.Controllers.CustomerCache
-> 00007F69D00335A0 System.Collections.Generic.List`1[[testwebapi.Controllers.Customer, DiagnosticScenarios]]
-> 00007F6C000148A0 testwebapi.Controllers.Customer[]
-> 00007F6AD0942258 testwebapi.Controllers.Customer
-> 00007F6AD09421F8 System.String
HandleTable:
00007F6C98BB15F8 (pinned handle)
-> 00007F6BDFFFF038 System.Object[]
-> 00007F69D0033570 testwebapi.Controllers.Processor
-> 00007F69D0033588 testwebapi.Controllers.CustomerCache
-> 00007F69D00335A0 System.Collections.Generic.List`1[[testwebapi.Controllers.Customer, DiagnosticScenarios]]
-> 00007F6C000148A0 testwebapi.Controllers.Customer[]
-> 00007F6AD0942258 testwebapi.Controllers.Customer
-> 00007F6AD09421F8 System.String
Found 2 roots.
Anda dapat melihat bahwa String langsung dipegang oleh Customer objek dan secara tidak langsung dipegang oleh CustomerCache objek.
Anda dapat terus memindahkan objek untuk melihat bahwa sebagian besar String objek mengikuti pola yang sama. Pada titik ini, investigasi memberikan informasi yang memadai untuk mengidentifikasi akar penyebab dalam kode Anda.
Prosedur umum ini memungkinkan Anda mengidentifikasi sumber kebocoran memori utama.
Membersihkan sumber daya
Dalam tutorial ini, Anda memulai contoh server web. Server ini seharusnya dimatikan seperti yang dijelaskan di bagian Mulai ulang proses yang gagal .
Anda juga dapat menghapus file cadangan yang dibuat.
Lihat juga
- dotnet-trace untuk menampilkan proses
- dotnet-counters untuk memeriksa penggunaan memori terkelola
- dotnet-dump untuk mengumpulkan dan menganalisis file cadangan
- dotnet/diagnostik
- Menggunakan Visual Studio untuk men-debug kebocoran memori