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

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

Příznaky

K narušení přístupu dochází při pokusu o volání spravovaného kódu prostřednictvím ukazatelů na funkce, které byly získány od spravovaných delegátů. Tato selhání, i když se nejedná o běžné chyby modulu CLR (Language Runtime), se může zdát, že tomu tak je, protože k narušení přístupu dochází v kódu CLR.

Selhání není konzistentní; někdy je volání ukazatele funkce úspěšné a někdy se nezdaří. K selhání může dojít pouze při velkém zatížení nebo při náhodném počtu pokusů.

Příčina

Delegát, ze kterého byl vytvořen ukazatel na funkci 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 zdá být 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 uvolnění paměti po zpětném volání a volání proběhne úspěšně. Jindy dojde 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 seřaďováním delegáta a zpětného volání ukazatele funkce a na frekvenci uvolňování paměti. Selhání je sporadické, pokud je čas mezi seřaďováním delegáta a následné zpětné volání krátký. K tomu obvykle dochází v případě, že nespravovaná metoda přijímající ukazatel na funkci neuloží ukazatel na funkci pro pozdější použití, ale místo toho okamžitě zavolá zpět na ukazatel funkce, aby před vrácením dokončila svou operaci. Podobně k dalšímu uvolňování paměti dochází, když je systém pod velkým zatížením, což s větší pravděpodobností, že dojde k uvolňování paměti před zpětným voláním.

Řešení

Jakmile je delegát seřazený jako ukazatel nespravované funkce, systém uvolňování paměti nemůže sledovat jeho životnost. Místo toho musí váš kód uchovávat odkaz na delegáta po celou dobu životnosti ukazatele nespravované funkce. Než to ale budete moct udělat, musíte nejprve zjistit, který delegát se shromáždil. Po aktivaci MDA poskytuje název typu delegáta. Tento název použijte k vyhledání kódu pro volání platformy nebo podpisy modelu COM, které tento delegát předávají nespravovanému kódu. Urážený delegát je předán prostřednictvím jednoho z těchto webů volání. Můžete také povolit gcUnmanagedToManaged MDA, aby vynutil uvolňování paměti před každým zpětným voláním do modulu runtime. Tím se odstraní nejistota způsobená uvolňováním paměti tím, že zajistíte, aby uvolňování paměti vždy probíhalo před zpětným voláním. Jakmile budete vědět, který delegát byl shromážděn, změňte kód tak, aby odkazoval na tohoto delegáta na spravované straně po celou dobu životnosti ukazatele nespravované funkce.

Vliv na modul runtime

Když jsou delegáti seřazeni jako ukazatele na funkce, modul runtime přidělí blok, který provede přechod z nespravovaného na spravovaný. Tento útržek je to, co nespravovaný kód ve skutečnosti volá před tím, než se nakonec vyvolá spravovaný delegát. callbackOnCollectedDelegate Bez povolení MDA se při shromáždění delegáta odstraní nespravovaný kód marshallingu. Když je callbackOnCollectedDelegate povolená analýza MDA, nespravovaný kód marshallingu se při shromáždění delegáta okamžitě neodstraní. Místo toho se posledních 1 000 instancí ve výchozím nastavení udržuje při životě a při zavolání se změní tak, aby aktivoval MDA. Po shromáždění dalších 1 001 delegátů se tento blok nakonec odstraní.

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é funkce ukazatel.

Konfigurace

Následující příklad ukazuje možnosti konfigurace aplikace. Nastaví počet útržků, které MDA udržuje při životě, 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 tento 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é