Aracılığıyla paylaş


callbackOnCollectedDelegate MDA

Not

Bu makale .NET Framework'e özgüdür. .NET 6 ve sonraki sürümleri de dahil olmak üzere daha yeni .NET uygulamaları için geçerli değildir.

Yönetilen callbackOnCollectedDelegate hata ayıklama yardımcısı (MDA), bir temsilci yönetilen koddan yönetilmeyen koda bir işlev işaretçisi olarak sıralanmışsa ve temsilci çöp toplandıktan sonra bu işlev işaretçisine geri çağırma yerleştirildiğinde etkinleştirilir.

Belirtiler

Erişim ihlalleri, yönetilen temsilcilerden alınan işlev işaretçileri aracılığıyla yönetilen koda çağrılmaya çalışılırken oluşur. Bu hatalar, yaygın dil çalışma zamanı (CLR) hataları olmasa da, erişim ihlali CLR kodunda oluştuğundan böyle görünebilir.

Hata tutarlı değil; bazen işlev işaretçisi üzerindeki çağrı başarılı olur ve bazen başarısız olur. Hata yalnızca ağır yük altında veya rastgele sayıda denemede oluşabilir.

Neden

İşlev işaretçisinin oluşturulduğu ve yönetilmeyen koda sunulduğu temsilci çöp olarak toplandı. Yönetilmeyen bileşen işlev işaretçisini çağırmaya çalıştığında erişim ihlali oluşturur.

Çöp toplamanın ne zaman gerçekleştiğine bağlı olduğundan hata rastgele görünür. Bir temsilci toplama için uygunsa, geri arama ve çağrı başarılı olduktan sonra çöp toplama gerçekleşebilir. Diğer durumlarda, geri çağırmadan önce çöp toplama gerçekleşir, geri arama bir erişim ihlali oluşturur ve program durur.

Hata olasılığı, temsilciyi hazırlama ile işlev işaretçisinde geri çağırma arasındaki süreye ve çöp toplama sıklığına bağlıdır. Temsilciyi sıralama ile geri çağırmanın süresi kısaysa hata düzensizdir. Bu durum genellikle işlev işaretçisini alan yönetilmeyen yöntemin işlev işaretçisini daha sonra kullanmak üzere kaydetmemesi, bunun yerine geri dönmeden önce işlemini tamamlamak için işlev işaretçisini hemen geri çağırması durumunda geçerlidir. Benzer şekilde, bir sistem ağır yük altında olduğunda daha fazla çöp toplama gerçekleşir ve bu da geri çağırmadan önce çöp toplamanın gerçekleşmesini daha olası hale getirir.

Çözüm

Bir temsilci yönetilmeyen işlev işaretçisi olarak sıralandıktan sonra, çöp toplayıcı ömrünü izleyemez. Bunun yerine, kodunuzun yönetilmeyen işlev işaretçisinin ömrü boyunca temsilciye bir başvuru tutması gerekir. Ancak bunu yapabilmeniz için önce hangi temsilcinin toplandığını belirlemeniz gerekir. MDA etkinleştirildiğinde, temsilcinin tür adını sağlar. Bu adı kullanarak kodunuzu platform çağrısı veya bu temsilciyi yönetilmeyen koda geçiren COM imzaları için arayın. Sorunlu temsilci bu arama sitelerinden biri üzerinden geçirilir. Ayrıca, çalışma zamanına gcUnmanagedToManaged yapılan her geri çağırmadan önce MDA'nın bir çöp toplamayı zorlamasını da etkinleştirebilirsiniz. Bu, bir çöp toplama işleminin her zaman geri çağırmadan önce gerçekleşmesini sağlayarak çöp toplamanın neden olduğu belirsizliği ortadan kaldırır. Hangi temsilcinin toplandığını öğrendikte, kodunuzu değiştirerek bu temsilciye başvuruyu yönetilen tarafta, yapılandırılmış yönetilmeyen işlev işaretçisinin ömrü boyunca koruyun.

Çalışma Zamanı üzerindeki etkisi

Temsilciler işlev işaretçileri olarak sıralandığında, çalışma zamanı yönetilmeyenden yönetilene geçişi sağlayan bir thunk ayırır. Yönetilen temsilci sonunda çağrılmadan önce yönetilmeyen kodun aslında çağıran şey budur. callbackOnCollectedDelegate MDA etkinleştirilmeden, temsilci toplandığında yönetilmeyen sıralama kodu silinir. callbackOnCollectedDelegate MDA etkinleştirildiğinde, temsilci toplandığında yönetilmeyen sıralama kodu hemen silinmez. Bunun yerine, son 1.000 örnek varsayılan olarak canlı tutulur ve çağrıldığında MDA'yı etkinleştirmek için değiştirilir. 1.001 temsilci daha toplandıktan sonra thunk sonunda silinir.

Çıktı

MDA, yönetilmeyen işlev işaretçisinde geri çağırma denenmeden önce toplanan temsilcinin tür adını bildirir.

Yapılandırma

Aşağıdaki örnekte uygulama yapılandırma seçenekleri gösterilmektedir. MDA'nın canlı tuttuğu thunk sayısını 1.500'e ayarlar. Varsayılan listSize değer 1.000, en az 50 ve en fazla 2.000'dir.

<mdaConfig>
  <assistants>
    <callbackOnCollectedDelegate listSize="1500" />
  </assistants>
</mdaConfig>

Örnek

Aşağıdaki örnekte bu MDA'nın etkinleştirebileceği bir durum gösterilmektedir:

// 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"); }
}

Ayrıca bkz.