callbackOnCollectedDelegate MDA

callbackOnCollectedDelegate Asystent zarządzanego debugowania (MDA) jest aktywowany, jeśli delegat jest marshalled z zarządzanego do niezarządzanego kodu jako wskaźnika funkcji, a wywołanie zwrotne jest umieszczane w tym wskaźniku funkcji po odśmieceniu pamięci delegata.

Objawy

Naruszenia dostępu występują podczas próby wywołania kodu zarządzanego za pomocą wskaźników funkcji uzyskanych od zarządzanych delegatów. Te błędy, chociaż nie są to usterki środowiska uruchomieniowego języka wspólnego (CLR), mogą wydawać się takie, ponieważ naruszenie dostępu występuje w kodzie CLR.

Awaria nie jest spójna; czasami wywołanie wskaźnika funkcji kończy się powodzeniem i czasami kończy się niepowodzeniem. Awaria może wystąpić tylko pod dużym obciążeniem lub w losowej liczbie prób.

Przyczyna

Delegat, z którego utworzono wskaźnik funkcji i uwidocznił niezarządzany kod, został usunięty. Gdy składnik niezarządzany próbuje wywołać wskaźnik funkcji, generuje naruszenie dostępu.

Awaria jest wyświetlana losowo, ponieważ zależy od tego, kiedy nastąpi odzyskiwanie pamięci. Jeśli pełnomocnik kwalifikuje się do odzyskiwania, odzyskiwanie pamięci może nastąpić po wywołaniu zwrotnym i wywołanie zakończy się powodzeniem. W innych przypadkach odzyskiwanie pamięci następuje przed wywołaniem zwrotnym, wywołanie zwrotne generuje naruszenie dostępu, a program zatrzymuje się.

Prawdopodobieństwo awarii zależy od czasu między marshalling delegata a wywołaniem zwrotnym wskaźnika funkcji, a także częstotliwością odzyskiwania pamięci. Błąd jest sporadyczne, jeśli czas między marshalling delegata i wywołania zwrotnego jest krótki. Zwykle dzieje się tak, jeśli niezarządzana metoda odbierana przez wskaźnik funkcji nie zapisuje wskaźnika funkcji do późniejszego użycia, ale zamiast tego wywołuje wskaźnik funkcji natychmiast, aby ukończyć operację przed zwróceniem. Podobnie więcej odzyskiwania pamięci występuje, gdy system jest pod dużym obciążeniem, co zwiększa prawdopodobieństwo wystąpienia odzyskiwania pamięci przed wywołaniem zwrotnym.

Rozwiązanie

Gdy delegat zostanie wyprowadzony jako wskaźnik funkcji niezarządzanej, moduł odśmiecanie pamięci nie może śledzić jego okresu istnienia. Zamiast tego kod musi przechowywać odwołanie do delegata przez okres istnienia wskaźnika funkcji niezarządzanej. Jednak zanim będzie to możliwe, musisz najpierw określić, który delegat został zebrany. Po aktywowaniu mda podaje nazwę typu delegata. Użyj tej nazwy, aby wyszukać kod dla wywołań platformy lub podpisów COM, które przekazują ten delegat do niezarządzanych kodów. Obiekt delegujący jest przekazywany przez jedną z tych witryn połączeń. Możesz również włączyć funkcję gcUnmanagedToManaged MDA, aby wymusić odzyskiwanie pamięci przed każdym wywołaniem zwrotnym w środowisku uruchomieniowym. Spowoduje to usunięcie niepewności wprowadzonej przez odzyskiwanie pamięci przez zapewnienie, że odzyskiwanie pamięci zawsze występuje przed wywołaniem zwrotnym. Gdy już wiesz, jaki delegat został zebrany, zmień kod, aby zachować odwołanie do tego delegata po stronie zarządzanej przez cały okres istnienia wskaźnika funkcji niezarządzanej marshalled.

Wpływ na środowisko uruchomieniowe

Gdy delegaci są marshalled jako wskaźniki funkcji, środowisko uruchomieniowe przydziela thunk, który przechodzi z niezarządzanych do zarządzanych. Ten thunk jest tym, co niezarządzany kod faktycznie wywołuje przed wywołanie zarządzanego delegata. Bez włączonego mdA callbackOnCollectedDelegate niezarządzany kod marshallingu jest usuwany po zebraniu delegata. Po włączeniu callbackOnCollectedDelegate mdA niezarządzany kod marshallingu nie jest natychmiast usuwany po zebraniu delegata. Zamiast tego ostatnie 1000 wystąpień jest domyślnie utrzymywanych przy życiu i zmienianych w celu aktywowania mda po wywołaniu. Thunk zostaje ostatecznie usunięty po zebraniu 1001 więcej delegatów marshalled.

Dane wyjściowe

Usługa MDA zgłasza nazwę typu delegata, który został zebrany przed próbą wywołania zwrotnego w wskaźniku funkcji niezarządzanej.

Konfigurowanie

W poniższym przykładzie przedstawiono opcje konfiguracji aplikacji. Ustawia liczbę thunks MDA utrzymuje przy życiu do 1500. Wartość domyślna listSize to 1000, wartość minimalna to 50, a wartość maksymalna to 2000.

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

Przykład

W poniższym przykładzie pokazano sytuację, która może aktywować tę usługę 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"); }  
}  

Zobacz też