Pergunta

Eu tenho 10 tópicos escrevendo milhares de pequenos buffers (16-30 bytes cada) para um arquivo enorme em posições aleatórias. Alguns dos tópicos jogar OutOfMemoryException em FileStream.Write (opreation).

O que está causando o OutOfMemoryException? O que procurar?

Eu estou usando o FileStream como este (para cada item escrito - este código é executado a partir de 10 tópicos diferentes):

using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite, BigBufferSizeInBytes, FileOptions.SequentialScan))
{
 ...
 fs.Write();
}

Eu suspeito que todos os buffers alocados dentro do FileStream não são liberados no tempo pelo GC. O que eu não entendo é por que a CLR, em vez de jogar, não basta executar um ciclo de GC e liberar todos os buffers não utilizados?

Nenhuma solução correta

Outras dicas

Se tópicos dez estão abrindo arquivos como seus programas de código, então você tem um máximo de dez undisposed FileStream objetos a qualquer momento. Sim, FileStream não tem um buffer interno, o tamanho do que você especificar com "BigBufferSizeInBytes" em seu código. Poderia, por favor divulgue o valor exato? Se este for grande o suficiente (por exemplo ~ 100MB), então ele poderia muito bem ser a fonte do problema.

Por padrão (ou seja, quando você não especificar um número em cima de construção), este tampão é 4kB e que é geralmente muito bem para a maioria das aplicações. Em geral, se você realmente se preocupam com o desempenho de gravação de disco, então você pode aumentar este para um par de 100 kB, mas não muito mais.

No entanto, para sua aplicação específica isso não faria muito sentido, como disse buffer nunca conterá mais do que a 16-30 bytes você escreve para ele antes de Dispose () do objeto FileStream.

Para responder à sua pergunta, um OutOfMemoryException é lançada apenas quando a memória solicitada não pode ser alocado depois a GC foi executado. Novamente, se o buffer é muito grande, então o sistema poderia ter muita memória à esquerda, não apenas um contígua pedaço. Isso ocorre porque o heap de objeto grande nunca é compactado.

Eu lembrou as pessoas sobre este algumas vezes, mas o Grande objeto pilha pode lançar essa exceção bastante subtially, quando aparentemente você tem pleanty de memória disponível ou o aplicativo é executado em OK.

Eu tenho que correr para esta questão com bastante frequência ao fazer quase exactally que seu discribing aqui.

Você precisa postar mais de seu código para responder a esta pergunta corretamente. No entanto, eu estou supondo que ele também poderia estar relacionado a um problema Halloween potencial (assustador Dooky) .

Seu tampão para o qual você está lendo a partir também pode ser o problema (montão objeto novamente grande relacionada) também novamente, você precisa colocar mais detalhes sobre o que está acontecendo lá no circuito. Acabei pregado o último bug eu tive que é praticamente idêntica (estou realizando muitas de atualização de hash paralelo que todos requerem estado independente de ser mantida através da leitura do arquivo de entrada) ....

OOP! apenas rolado sobre e notou "BigBufferSizeInBytes", eu estou inclinado para Large Object Heap de novo ...

Se eu fosse você, (e isto é extremamente difícil devido à falta de contexto), eu daria uma pequena expedição "mbuf", onde você copiou dentro e para fora, em vez de permitir que todos os seus disperate fio de ler individualmente através sua matriz backing grande ... (ou seja, é difícil não causa alocações insadential com sintaxe do código muito sutil).

Os amortecedores não são geralmente atribuídos dentro do FileStream. Talvez o problema é a linha de "escrever milhares de pequenos buffers" - você realmente quer dizer isso? Normalmente você re-utilizar um buffer de muitas, muitas, muitas vezes (ou seja, em diferentes chamadas para leitura / gravação).

Também - este é um único arquivo? A única FileStream não é garantido para ser thread-safe ... por isso, se você não está fazendo a sincronização, esperar caos.

É possível que essas limitações surgem a partir do sistema operacional subjacente, e que o .NET Framework é impotente para superar este tipo de limitações.

O que não se pode deduzir do seu exemplo de código é se você abrir um monte deles FileStream objetos ao mesmo tempo, ou abri-los muito rápido em sequência. O uso do 'usando' palavra-chave irá certificar-se de que os arquivos estão fechados após a chamada fs.Write (). Não há nenhum ciclo de GC necessário para fechar o arquivo.

A classe FileStream é realmente voltada para o acesso de leitura / gravação seqüencial de arquivos. Se você precisa escrever rapidamente para locais aleatórios em um arquivo grande, você pode querer dar uma olhada usando mapeamento de arquivo virtual.

Update: Parece que o mapeamento de arquivos virtual não será suportado oficialmente em .NET até 4.0. Você pode querer dar uma olhada em implementações de terceiros para essa funcionalidade.

Dave

Eu estou experimentando algo semelhante e se perguntou se alguma vez fixado para baixo a raiz de seu problema?

Meu código faz um monte de copiar entre arquivos, passando muito poucos megas entre diferentes arquivos byte. Tenho notado que, embora as estadias de uso de memória do processo dentro de um intervalo razoável, a alocação brotos de memória do sistema até muito elevados durante a cópia - muito mais do que está sendo usado por meu processo.

Eu rastreou o baixo questão para o FileStream.Write () chamada - quando esta linha é retirado, o uso de memória parece ir como esperado. Meus BigBufferSizeInBytes é o padrão (4k), e eu não posso ver em qualquer lugar onde estes poderiam estar a recolher ...

Qualquer coisa que você descobriu enquanto olhando para o seu problema seria recebido com gratidão!

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