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.
Note
Artikel ini khusus untuk .NET Framework. Ini tidak berlaku untuk implementasi .NET yang lebih baru, termasuk .NET 6 dan versi yang lebih baru.
Asisten callbackOnCollectedDelegate penelusuran kesalahan terkelola (MDA) diaktifkan jika delegasi dikumpulkan dari kode yang dikelola ke tidak dikelola sebagai penunjuk fungsi dan panggilan balik ditempatkan pada penunjuk fungsi tersebut setelah delegasi dikumpulkan sampah.
Gejala
Pelanggaran akses terjadi saat mencoba memanggil ke kode terkelola melalui penunjuk fungsi yang diperoleh dari delegasi terkelola. Kegagalan ini, meskipun bukan bug runtime bahasa umum (CLR), mungkin tampak demikian karena pelanggaran akses terjadi dalam kode CLR.
Kegagalan tidak konsisten; terkadang panggilan pada penunjuk fungsi berhasil dan terkadang gagal. Kegagalan mungkin hanya terjadi di bawah beban berat atau pada sejumlah upaya acak.
Penyebab
Delegasi tempat penunjuk fungsi dibuat dan diekspos ke kode yang tidak dikelola adalah sampah yang dikumpulkan. Ketika komponen yang tidak dikelola mencoba memanggil penunjuk fungsi, komponen tersebut menghasilkan pelanggaran akses.
Kegagalan muncul secara acak karena tergantung pada kapan pengumpulan sampah terjadi. Jika delegasi memenuhi syarat untuk pengumpulan, pengumpulan sampah dapat terjadi setelah panggilan balik dan panggilan berhasil. Di lain waktu, pengumpulan sampah terjadi sebelum panggilan balik, panggilan balik menghasilkan pelanggaran akses, dan program berhenti.
Probabilitas kegagalan tergantung pada waktu antara marshalling delegasi dan panggilan balik pada penunjuk fungsi serta frekuensi pengumpulan sampah. Kegagalan ini sporadis jika waktu antara marshalling delegasi dan panggilan balik berikutnya singkat. Ini biasanya terjadi jika metode yang tidak dikelola yang menerima penunjuk fungsi tidak menyimpan penunjuk fungsi untuk digunakan nanti tetapi sebaliknya memanggil kembali pada penunjuk fungsi segera untuk menyelesaikan operasinya sebelum kembali. Demikian pula, pengumpulan sampah lebih banyak terjadi ketika sistem berada di bawah beban berat, yang membuatnya lebih mungkin pengumpulan sampah akan terjadi sebelum panggilan balik.
Resolution
Setelah delegasi dikumpulkan sebagai penunjuk fungsi yang tidak dikelola, pengumpul sampah tidak dapat melacak masa pakainya. Sebagai gantinya, kode Anda harus menyimpan referensi ke delegasi selama masa pakai penunjuk fungsi yang tidak dikelola. Tetapi sebelum Anda dapat melakukan itu, Anda harus mengidentifikasi delegasi mana yang dikumpulkan. Saat MDA diaktifkan, MDA menyediakan nama jenis delegasi. Gunakan nama ini untuk mencari kode Anda untuk memanggil platform atau tanda tangan COM yang meneruskan yang mendelegasikan ke kode yang tidak dikelola. Delegasi yang menyinggung diteruskan melalui salah satu situs panggilan ini. Anda juga dapat mengaktifkan gcUnmanagedToManaged MDA untuk memaksa pengumpulan sampah sebelum setiap panggilan balik ke runtime. Ini akan menghapus ketidakpastian yang diperkenalkan oleh pengumpulan sampah dengan memastikan bahwa pengumpulan sampah selalu terjadi sebelum panggilan balik. Setelah Anda mengetahui delegasi apa yang dikumpulkan, ubah kode Anda untuk menyimpan referensi ke delegasi tersebut di sisi terkelola selama masa pakai penunjuk fungsi yang tidak dikelola secara marshal.
Efek pada Runtime
Ketika delegasi di-marshalled sebagai penunjuk fungsi, runtime mengalokasikan thunk yang melakukan transisi dari tidak dikelola ke dikelola. Thunk inilah yang sebenarnya dipanggil oleh kode yang tidak dikelola sebelum delegasi terkelola akhirnya dipanggil.
callbackOnCollectedDelegate Tanpa MDA diaktifkan, kode marshalling yang tidak dikelola dihapus saat delegasi dikumpulkan.
callbackOnCollectedDelegate Dengan MDA diaktifkan, kode marshalling yang tidak dikelola tidak segera dihapus ketika delegasi dikumpulkan. Sebagai gantinya, 1.000 instans terakhir tetap hidup secara default dan diubah untuk mengaktifkan MDA saat dipanggil. Thunk akhirnya dihapus setelah 1.001 lebih delegasi marshalled dikumpulkan.
Hasil
MDA melaporkan nama jenis delegasi yang dikumpulkan sebelum panggilan balik dicoba pada penunjuk fungsi yang tidak dikelola.
Konfigurasi
Contoh berikut menunjukkan opsi konfigurasi aplikasi. Ini mengatur jumlah thunks MDA tetap hidup menjadi 1.500. Nilai defaultnya listSize adalah 1.000, minimumnya adalah 50, dan maksimumnya adalah 2.000.
<mdaConfig>
<assistants>
<callbackOnCollectedDelegate listSize="1500" />
</assistants>
</mdaConfig>
Example
Contoh berikut menunjukkan situasi yang dapat mengaktifkan MDA ini:
// Library.cpp : Defines the unmanaged entry point for the DLL application.
#include "windows.h"
#include "stdio.h"
void (__stdcall *g_pfTarget)();
void __stdcall Initialize(void __stdcall pfTarget())
{
g_pfTarget = pfTarget;
}
void __stdcall Callback()
{
g_pfTarget();
}
// C# Client
using System;
using System.Runtime.InteropServices;
public class Entry
{
public delegate void DCallback();
public static void Main()
{
new Entry();
Initialize(Target);
GC.Collect();
GC.WaitForPendingFinalizers();
Callback();
}
public static void Target()
{
}
[DllImport("Library", CallingConvention = CallingConvention.StdCall)]
public static extern void Initialize(DCallback pfDelegate);
[DllImport ("Library", CallingConvention = CallingConvention.StdCall)]
public static extern void Callback();
~Entry() { Console.Error.WriteLine("Entry Collected"); }
}