Pergunta

Eu tenho um problema onde um par 3 matrizes dimensionais alocar uma quantidade enorme de memória e o programa às vezes precisa substituí-los com maiores queridos / menores e lança um OutOfMemoryException.

Exemplo: há 5 matrizes alocados 96MB (200x200x200, 12 bytes de dados em cada entrada) e as necessidades de programa para substituí-los com 210x210x210 (111MB). Ele faz isso de uma maneira semelhante a esta:

array1 = new Vector3[210,210,210];

Onde Array1-array5 são os mesmos campos utilizados anteriormente. Este deve definir as velhas matrizes como candidatos para a coleta de lixo, mas que aparentemente o GC não agir rápido o suficiente e as folhas das antigas matrizes alocados antes de alocar os novos - o que faz com que o OOM - enquanto se onde libertado antes de as novas alocações de espaço deve ser suficiente.

O que eu estou procurando é uma maneira de fazer algo como isto:

GC.Collect(array1) // this would set the reference to null and free the memory
array1 = new Vector3[210,210,210];

Eu não tenho certeza se um collecion lixo completa seria uma boa idéia já que o código pode (em algumas situações) precisam ser executadas com bastante frequência.

Existe uma maneira correta de fazer isso?

Foi útil?

Solução

Isto não é uma resposta exata para a pergunta original, "como forçar GC', no entanto, eu acho que vai ajudá-lo a reexaminar o problema.

Depois de ver o seu comentário,

  • Colocar o GC.Collect (); parece ajudar, altought isso ainda não resolve o problema completamente - por algum motivo o programa ainda trava quando cerca de 1,3 GB são alocados (estou usando System.GC.GetTotalMemory (false); para encontrar a quantidade verdadeira alocado).

Vou suspeitar que você pode ter memória fragmentação . Se o objeto for grande (85000 bytes em .NET CLR 2.0, se bem me lembro, eu não sei se ele foi alterado ou não), o objeto será alocado em uma pilha especial, Large Object Heap (LOH) . GC faz recuperar a memória que está sendo usado por objetos inacessíveis em LOH, ainda, ele não executa a compactação, em LOH como faz para outros montes (Gen0, gen1 e gen2), devido ao desempenho.

Se você frequentemente alocar e desalocar objetos grandes, ele vai fazer LOH fragmentado e mesmo que você tenha mais memória livre no total do que o que você precisa, você não pode ter um espaço de memória contígua mais, portanto, terá exceção OutOfMemory.

Eu posso pensar duas soluções neste momento.

  1. Mover para 64-bit máquina / OS e tirar proveito dela :) (mais fácil, mas possivelmente mais difícil assim dependendo de suas limitações de recursos)
  2. Se você não pode fazer # 1, em seguida, tentar alocar um enorme chuck de memória primeiro e usá-los (pode exigir a escrever algumas classe auxiliar para manipular uma matriz menor, que por reside fatos em uma matriz maior) para fragmentação evitar . Isso pode ajudar um pouco, no entanto, pode não resolver completamente o problema e você pode ter que lidar com a complexidade.

Outras dicas

Parece que você correr para LOH (heap de objeto grande) problema de fragmentação.

Large Object Heap

CLR Inside Out Large Object Heap Descoberto

Você pode verificar para ver se você está tendo problemas loh fragmentação usando SOS

Marque esta questão para um exemplo de como usar o SOS para inspecionar o loh.

Forçar uma coleta de lixo nem sempre é uma boa idéia (que pode realmente promover a vida útil dos objetos em algumas situações). Se você tem que, você usaria:

array1 = null;
GC.Collect();
array1 = new Vector3[210,210,210];

Não é isto apenas grande fragmentação objeto pilha? Objectos> 85.000 bytes são alocados no heap de objeto grande. O GC libera espaço no este montão, mas nunca compacta os objetos restantes. Isso pode resultar em memória contígua insufficent para alocar com êxito um objeto grande.

Alan.

Se eu tivesse a especular que você problema não é realmente que você está indo de Vector3 [200200200] para um Vector3 [210210210], mas que provavelmente você tem etapas anteriores semelhantes antes esta:

 i.e.   
    // first you have
    Vector3[10,10,10];
    // then
    Vector3[20,20,20];
    // then maybe
    Vector3[30,30,30];
    //  .. and so on ..
    //  ...
    // then
    Vector3[200,200,200];
    // and eventually you try
    Vector3[210,210,210] // and you get an OutOfMemoryException..

Se isso for verdade, gostaria de sugerir uma melhor estratégia de alocação. Tente sobre a alocação - talvez dobrando o tamanho de cada vez ao invés de sempre alocar apenas o espaço que você precisa. Especialmente se estas matrizes são sempre usados ??por objectos que necessidade de fixar os tampões (isto é, se que tem ligações com o código nativo)

Assim, em vez do acima exposto, ter algo como isto:

 // first start with an arbitrary size
 Vector3[64,64,64];
 // then double that
 Vector3[128,128,128];
 // and then.. so in thee steps you go to where otherwise 
 // it would have taken you 20..
 Vector3[256,256,256];

Eles podem não estar sendo recolhidos, porque eles estão sendo referenciado em algum lugar você não está esperando.

Como um teste, tente alterar as referências a WeakReferences em vez e ver se isso resolve o seu problema OOM. Se isso não acontecer, então você está referenciando-los em outro lugar.

Eu entendo o que você está tentando fazer e empurrando para coleta de lixo imediato provavelmente não é a abordagem correta (uma vez que a GC é sutil em suas formas e rápido de raiva).

Dito isto, se você deseja essa funcionalidade, porque não criá-lo?

public static void Collect(ref object o)
{
    o = null;
    GC.Collect();
}

Um OutOfMemory exceção dispara internamente um ciclo de GC automaticamente uma vez e as tentativas de alocação de novo antes de realmente lançar a exceção ao seu código. A única maneira que você poderia ter exceções OutOfMemory é se você está segurando as referências a muita memória. Desmarque as referências, o mais rapidamente possível, atribuindo-lhes nulo.

Parte do problema pode ser que você está alocando um array multidimensional, que é representado como um único bloco contíguo de memória no heap objeto grande (mais detalhes aqui ). Isso pode bloquear outras atribuições, como não há um bloco contíguo livre para uso, mesmo se ainda há algum espaço livre em algum lugar, daí o OOM.

Tente alocar-lo como uma matriz irregulares - Vector3 [210] [210] [210] - que se espalha as matrizes em torno de memória em vez de como um único bloco, e ver se isso melhora as questões

John, Criando objetos> 85000 bytes fará o fim objeto para cima na grande pilha de objetos. Heap de objeto grande nunca é compactado, em vez do espaço livre é reutilizado novamente. Isto significa que se você está alocando matrizes maiores cada vez, você pode acabar em situações onde LOH é fragmentado, daí o OOM.

Você pode verificar este for o caso, quebrando com o depurador no ponto de OOM e obter um despejo, submeter este despejo de MS através de um bug connect ( http://connect.microsoft.com ) seria um grande começo.

O que posso garantir é que a GC vai fazer a coisa certa a tentar satisfazê-lo pedido de atribuição, o que inclui dando início a uma GC para limpar o lixo velho para satisfazer os novos pedidos de atribuição.

Eu não sei o que é a política de partilha de fora despejos de memória em Stackoverflow, mas eu ficaria feliz em dar uma olhada para entender o seu problema mais.

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