Sdílet prostřednictvím


callbackOnCollectedDelegate – pomocník spravovaného ladění (MDA)

Poznámka:

Tento článek je specifický pro rozhraní .NET Framework. Nevztahuje se na novější implementace .NET, včetně .NET 6 a novějších verzí.

Pomocník callbackOnCollectedDelegate spravovaného ladění (MDA) se aktivuje, pokud je delegát zařazován ze spravovaného na nespravovaný kód jako ukazatel funkce a zpětné volání se na tento ukazatel funkce umístí po uvolnění paměti delegáta.

Příznaky

K narušení přístupu dochází při pokusu o volání spravovaného kódu prostřednictvím ukazatelů funkce, které byly získány ze spravovaných delegátů. Tato selhání, i když nejsou běžné chyby modulu CLR (Language Runtime), se mohou zdát, že příčinou porušení přístupu je kód CLR.

Selhání není konzistentní; někdy volání ukazatele funkce proběhne úspěšně a někdy selže. K selhání může dojít pouze v případě velkého zatížení nebo náhodného počtu pokusů.

Příčina

Delegát, ze kterého byl vytvořen ukazatel funkce a vystavený nespravovanému kódu, byl uvolněn z paměti. Když se nespravovaná komponenta pokusí volat ukazatel funkce, vygeneruje narušení přístupu.

Selhání se zobrazí náhodně, protože závisí na tom, kdy dojde k uvolňování paměti. Pokud má delegát nárok na shromažďování, může dojít k uvolňování paměti po zpětném volání a volání proběhne úspěšně. Jindy dochází k uvolňování paměti před zpětným voláním, zpětné volání vygeneruje narušení přístupu a program se zastaví.

Pravděpodobnost selhání závisí na době mezi zařazováním delegáta a zpětného volání ukazatele funkce a četností uvolňování paměti. Selhání je občasné, pokud je čas mezi zařazováním delegáta a následného zpětného volání krátký. To je obvykle případ, pokud nespravovaná metoda přijímající ukazatel funkce neuloží ukazatel funkce pro pozdější použití, ale místo toho volá zpět ukazatel funkce okamžitě k dokončení své operace před vrácením. Podobně dochází k většímu uvolňování paměti v případě, že je systém zatížený velkým zatížením, což zvyšuje pravděpodobnost, že se před zpětným voláním provede uvolňování paměti.

Rozlišení

Jakmile se delegát zařadí jako ukazatel nespravované funkce, systém uvolňování paměti nemůže sledovat jeho životnost. Místo toho musí kód uchovávat odkaz na delegáta po dobu životnosti nespravovaného ukazatele funkce. Než to ale budete moct udělat, musíte nejdřív určit, který delegát se shromáždil. Po aktivaci MDA se zobrazí název typu delegáta. Tento název použijte k vyhledání kódu pro vyvolání platformy nebo podpisy modelu COM, které předávají delegáta na nespravovaný kód. Delegující delegát je předán prostřednictvím jednoho z těchto webů volání. MdA můžete také povolit gcUnmanagedToManaged vynucení uvolňování paměti před každým zpětným voláním do modulu runtime. Tím se odstraní nejistota zavedená uvolňováním paměti tím, že zajistí, aby se uvolňování paměti vždy objevilo před zpětným voláním. Jakmile budete vědět, jaký delegát byl shromážděn, změňte kód tak, aby odkazoval na tohoto delegáta na spravované straně po celou dobu životnosti zařazovaného nespravovaného ukazatele funkce.

Vliv na modul runtime

Když jsou delegáti zařazovány jako ukazatele na funkce, modul runtime přidělí blok, který provede přechod z nespravovaného na spravovaný. Tento blok dat je to, co nespravovaný kód skutečně volá před tím, než se spravovaný delegát konečně vyvolá. callbackOnCollectedDelegate Bez povolené správy mdA se po shromáždění delegáta odstraní nespravovaný kód seřazování. Když je callbackOnCollectedDelegate povolená funkce MDA, nespravovaný kód pro seřazování se okamžitě neodstraní při shromáždění delegáta. Místo toho se ve výchozím nastavení udržuje posledních 1 000 instancí naživu a při zavolání se změní aktivace MDA. Tento blok se nakonec odstraní po shromáždění 1 001 dalších zařazovaných delegátů.

Výstup

MdA hlásí název typu delegáta, který byl shromážděn před pokusem o zpětné volání na jeho nespravovaný ukazatel funkce.

Konfigurace

Následující příklad ukazuje možnosti konfigurace aplikace. Nastaví počet útržků, které MDA udržuje naživu na 1 500. Výchozí listSize hodnota je 1 000, minimum je 50 a maximum je 2 000.

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

Příklad

Následující příklad ukazuje situaci, která může aktivovat tuto mdA:

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

Viz také