Compartilhar via


callbackOnCollectedDelegate MDA

The callbackOnCollectedDelegate Assistente de depuração gerenciada (MDA) será ativado se um delegado empacotado de gerenciado para código não gerenciado sistema autônomo um ponteiro de função e um retorno de chamada é colocado desse ponteiro de função depois que o delegado for coletados pelo lixo.

Sintomas

Violações de acesso ocorrem durante a tentativa de telefonar código gerenciado através de ponteiros de função que foram obtidas a partir de delegados gerenciados.Essas falhas, ao mesmo tempo não comuns linguagem tempo de execução (CLR) bugs, poderá parecer fazer isso porque a violação de acesso ocorre no código do CLR.

A falha não é consistente; às vezes, telefonar no ponteiro de função for bem-sucedida e às vezes não.A falha pode ocorrer somente sob carga pesada ou em um número aleatório de tentativas.

Causa

O delegado a partir do qual o ponteiro de função foi criado e exposto a código não gerenciado estava coletados pelo lixo.Quando o componente não gerenciado tenta chamar no ponteiro de função, ele gera uma violação de acesso.

A falha aparece aleatória porque ele depende de quando lixo coleção ocorre.Se um delegado é qualificado para coleção, o lixo coleção podem ocorrer após o retorno de telefonar e a telefonar for bem-sucedida.Em outros momentos, o lixo coleção ocorre antes do retorno de chamada, o retorno de chamada gera uma violação de acesso e o programa pára.

A probabilidade da falha depende do time entre o delegado e o retorno de chamada no ponteiro de função, bem sistema autônomo a freqüência das coletas de marshaling.A falha é esporádica se o time entre o delegado e o retorno de chamada exibido de marshaling for curto.Isso geralmente é o caso se o método não gerenciado, recebendo o ponteiro de função não salva o ponteiro de função para uso posterior, mas em vez disso, chama de volta no ponteiro de função imediatamente para concluir sua operação antes de retornar.Da mesma forma, mais lixo coleção s ocorrer quando um sistema está sob carga pesada, o que torna mais provável que um lixo coleção ocorrerá antes do retorno de chamada.

Resolução

Depois de um delegado foi empacotado sistema autônomo um ponteiro de função não gerenciada, o coletor de lixo não pode controlar sua tempo de vida.Em vez disso, seu código deve manter uma referência ao delegado durante o tempo de vida do ponteiro de função não gerenciada.Mas, antes você pode fazer isso, você primeiro deve identificar delegado que foi coletado.Quando o MDA é ativado, ele fornece o nome do tipo do delegado.Use o nome de Pesquisar chamar seu código de plataforma ou COM assinaturas que passam esse delegado check-out para código não gerenciado.O delegado ofensivo é passado um desses sites de telefonar.Você também pode ativar o gcUnmanagedToManaged MDA para forçar um lixo coleção antes de cada retorno de chamada no tempo de execução. Isso removerá a incerteza introduzida pela coleta de lixo, garantindo sempre uma coleta de lixo ocorre antes do retorno de chamada.Você sabe qual delegado foi coletado, altere o código para manter uma referência a esse delegado no lado gerenciado durante a tempo de vida do ponteiro de função não gerenciada empacotado.

Efeito sobre o tempo de execução

Quando delegados são empacotados sistema autônomo ponteiros de função, o tempo de execução aloca uma conversão que faz a transição de não gerenciado a gerenciado.Essa conversão é o que o código não gerenciado realmente chama antes do gerenciado delegado é chamado por último.Sem o callbackOnCollectedDelegate MDA ativada, o código de marshaling não gerenciado é excluído quando o delegado é coletado. Com o callbackOnCollectedDelegate MDA ativada, o código de marshaling não gerenciado não é excluído imediatamente quando o delegado é coletado. Em vez disso, as instâncias de 1.000 pela última vez são mantidas vivas por padrão e alteradas para ativar o MDA quando chamado.A conversão intermediária eventualmente é excluída após a representantes mais empacotadas 1,001 são coletados.

Saída

O MDA informa o nome de tipo de delegado coletadas antes de um retorno de chamada foi tentado no seu ponteiro de função não gerenciada.

Configuração

O exemplo a seguir mostra as opções de configuração do aplicativo.Ele define o número de thunks que o MDA mantém vivo para 1.500.O padrão de listSize valor é 1.000, o mínimo é de 50 e o máximo é de 2.000.

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

Exemplo

O exemplo a seguir demonstra uma situação que pode ativar este 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"); }
}

Consulte também

Conceitos

Diagnosticar erros com assistentes de depuração gerenciadas

Visão geral do empacotamento interop

Referência

MarshalAsAttribute

gcUnmanagedToManaged MDA

Outros recursos

Interoperabilidade