Estratégias para vazamentos rastrear memória Quando você tiver feito tudo errado

StackOverflow https://stackoverflow.com/questions/600757

  •  03-07-2019
  •  | 
  •  

Pergunta

O meu programa, infelizmente, tem um vazamento de memória em algum lugar, mas eu vou ser amaldiçoado se eu sei o que é.

Seu trabalho é lido em um monte de arquivos ~ 2MB, fazer alguma substituição análise e corda, em seguida, enviá-las em vários formatos. Naturalmente, isso significa um monte de cordas, e assim fazendo shows rastreamento de memória que eu tenho um monte de cordas, que é exatamente o que eu esperaria. A estrutura do programa é uma série de aulas (cada um em seu próprio segmento, porque eu sou um idiot ) que atua sobre um objeto que representa cada arquivo na memória. (Cada objeto tem uma fila de entrada que usa um bloqueio em ambas as extremidades. Enquanto isso significa que eu começar a correr esse processamento simples em paralelo, isso também significa que tenho múltiplos 2MB objetos sentado na memória.) Estrutura de cada objeto é definido por um objeto de esquema .

As minhas classes de processamento elevar eventos quando eles fizeram o seu processamento e passar uma referência ao grande objeto que contém todas as minhas cordas para adicioná-lo para a fila do próximo objeto de processamento. Substituindo o evento com uma chamada de função para adicionar à fila não parar o vazamento. Um dos formatos de saída me obriga a usar um objeto não gerenciado. A implementação de Dispose () na classe não parar o vazamento. Eu já substituiu todas as referências para o objeto de esquema com um nome de índice. Não dados. Eu não tenho idéia do que está causando isso, e nenhuma idéia de onde procurar. O traço de memória não ajuda, porque tudo que eu vejo um monte de cordas que está sendo criado, e eu não vejo onde as referências são degola na memória.

Nós estamos indo muito bem desistir e back roll neste momento, mas eu tenho uma necessidade patológica de saber exatamente como eu estraguei isto. Eu sei Stack Overflow não pode exatamente pentear meu código, mas que estratégias você pode sugerir para rastrear esse vazamento para baixo? Eu provavelmente vou fazer isso no meu próprio tempo, de modo que qualquer abordagem é viável.

Foi útil?

Solução

Uma técnica que eu tentaria é reduzir sistematicamente a quantidade de código que você precisa para demonstrar o problema sem fazer o problema desaparecer. Esta é informalmente conhecida como "dividir e conquistar" e é uma técnica de depuração poderoso. Depois de ter um pequena exemplo que demonstra o mesmo problema, será muito mais fácil para você entender. Talvez o problema de memória ficará mais claro nesse ponto.

Outras dicas

Há apenas uma pessoa que pode ajudá-lo. o nome dessa pessoa é Tess Ferrandez . (Silêncio abafado)

Mas a sério. Leia seu blog (o primeiro artigo é bastante pertinente). Vendo como ela depura este material vai lhe dar um monte de visão profunda sobre saber o que está acontecendo com o seu problema.

Eu gosto do CLR Profiler da Microsoft. Ele fornece algumas grandes ferramentas para a visualização do heap gerenciado e rastrear vazamentos.

Eu uso o dotTrace profiler para rastrear vazamentos de memória. É muito mais determinista do que experimentação metodológica e erro e transforma-se resultados muito mais rápido.

Para quaisquer ações que executa sistema, eu tomo um instantâneo, em seguida, executar algumas iterações da função, em seguida, tomar outro instantâneo. Comparando os dois irá mostrar-lhe todos os objetos que foram criados no meio, mas não foram libertados. Você pode então ver o quadro de pilha no ponto de sua criação e, portanto, descobrir o que as instâncias não estão sendo liberados.

Get este: http://www.red-gate.com/ produtos / ants_profiler / index.htm

A memória e perfil de desempenho são impressionantes. Ser capaz de realmente ver os números adequados em vez de adivinhar torna a otimização muito rápido. Eu usei-o um pouco de trabalho para reduzir o consumo de memória do nosso aplicativo principal.

  1. Adicione o código para o construtor do objeto unamanaged para iniciar sessão quando é onstructed, e classificar uma identificação única. Use essa identificação única quando o objeto é destruída novamente, e você pode em menos dizer quais vão extraviados.
  2. Grep o código para cada lugar que você construir um novo objecto; seguir esse caminho de código para ver se você tem um correspondência destruir.
  3. Adicionar encadeamento ponteiros para a objetos construídos, então você tem um ligação ao objecto construído antes e depois do atual. Depois, você pode varrer através delas mais tarde.
  4. Adicionar contadores de referência.
  5. Existe uma "depuração malloc" disponível?

O add depuração gerido em SoS (Filho de greve) é imensamente potente para rastrear 'vazamentos' gerenciados de memória uma vez que são, por definição descoberta das raízes gc.

Ele vai trabalhar em WinDbg ou estúdio Visual (embora seja em muitos aspectos, mais fácil de usar em WinDbg)

Não é nada fácil de se familiarizar com. Aqui é um tutorial

Eu segundo a recomendação para verificar o blog de Tess Fernandez também.

Como você sabe para um fato que você realmente tem um vazamento de memória?

Uma outra coisa: Você escreve que suas classes de processamento estão usando eventos. Se você tiver registrado um manipulador de eventos que irá manter o objeto que possui o evento vivo - ou seja, o GC não pode cobrá-lo. Certifique-se de registrar todos os manipuladores de eventos se você quer seus objetos para ser lixo coletado.

Tenha cuidado como você define "vazamento". "Usa mais memória" ou mesmo "usa muita memória" não é o mesmo como "vazamento de memória". Isto é especialmente verdade em um ambiente de coleta de lixo. Pode ser simplesmente que GC não tem a necessidade de recolher a memória extra que você está vendo usado. Também deve ter cuidado sobre a diferença entre o uso de memória virtual e uso de memória física.

Finalmente nem todos os "vazamentos de memória" são causadas por tipos de "memória" de questões. Me disseram uma vez (não solicitado) para corrigir um vazamento de memória urgente que estava causando IIS para reiniciar com freqüência. Na verdade, eu fiz de perfil e descobri que eu estava usando um monte de cordas através da classe StringBuilder. Eu implementou um conjunto de objetos (de um artigo MSDN) para os StringBuilders, e uso de memória desceu substancialmente.

Ainda IIS reiniciado com a mesma frequência. Isso aconteceu porque não houve vazamento de memória. Em vez disso, houve código não gerenciado, que afirmava ser thread-safe, mas não foi. Usá-lo em um serviço web (múltiplos threads) causou a escrever todo o montão C Runtime Library. Uma vez que ninguém estava à procura de exceções não gerenciados, ninguém viu isso até aconteceu de eu fazer alguma profiling com AQtime de Automated QA. Isso acontece para ter uma janela de eventos, que passou a exibir os gritos de dor do Runtime Library C.

bloqueios colocados ao redor do chamadas para o código não gerenciado, e o "vazamento de memória" foi embora.

Se o objeto não gerenciado é realmente a causa do vazamento, você pode querer tê-lo chamar AddMemoryPressure quando ele aloca memória não gerenciada e RemoveMemoryPressure em Finalize / Dispose / onde quer que retira a atribuição de memória não gerenciada. Isto dará ao GC um melhor controle sobre a situação, porque ele pode não perceber que há uma necessidade de recolha cronograma contrário.

Você mencionou que o uso de eventos. Você está removendo os manipuladores desses eventos quando o seu feito com o seu objeto? Descobri que os manipuladores de eventos 'soltas' vai causar uma série de problemas de vazamento de memória se você adicionar um monte de manipuladores sem removê-los quando seu feito.

A melhor ferramenta de perfil de memória para .Net é esta:

http://memprofiler.com

Além disso, enquanto eu estou aqui, o melhor profiler desempenho para .Net é esta:

http://www.yourkit.com/dotnet/download/index.jsp

Eles também são de grande valor para o dinheiro, têm custos fixos baixos e são fáceis de usar. Qualquer um sério sobre o desenvolvimento .Net deve considerar ambos um investimento pessoal e compra imediatamente. Ambos têm um teste gratuito.

Eu trabalho em um motor de jogo em tempo real com mais de 700k linhas de código escrito em C # e gastaram centenas de horas usando ambas as ferramentas. Eu tenho usado o produto Sci tecnologia desde 2002 e YourKit! nos últimos três anos. Embora eu tentei muito poucos dos outros que eu sempre voltava a estes.

IMHO, ambos são absolutamente brilhante.

Assim como Charlie Martin, você pode fazer algo como isto:

static unigned __int64 _foo_id = 0;
foo::foo()
{
    ++_foo_id;
    if (_foo_id == MAGIC_BAD_ALLOC_ID)
        DebugBreak();
    std::werr << L"foo::foo @ " << _foo_id << std::endl;
}
foo::~foo()
{
    --_foo_id;
    std::werr << L"foo::~foo @ " << _foo_id << std::endl;
}

Se você pode recriá-lo, mesmo uma ou duas vezes com o mesmo ID de alocação, isso vai deixar você olhar para o que está acontecendo ali mesmo (obviamente TLS / rosqueamento tem de ser tratado, bem como, se necessário, mas eu deixei -lo para maior clareza).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top