Eu li sobre Gerações e heap de objeto grande. Mas ainda não consigo entender qual é o significado (ou benefício) de ter um heap de objeto grande?
O que poderia ter dado errado (em termos de desempenho ou memória) se CLR tivesse contado apenas com a Geração 2 (considerando que o limite para Gen0 e Gen1 é pequeno para lidar com objetos grandes) para armazenar objetos grandes?
.net
garbage-collection
clr
large-object-heap
Manish Basantani
fonte
fonte
Respostas:
Uma coleta de lixo não apenas elimina os objetos não referenciados, mas também compacta o heap. Essa é uma otimização muito importante. Isso não apenas torna o uso da memória mais eficiente (sem falhas não utilizadas), mas torna o cache da CPU muito mais eficiente. O cache é realmente um grande negócio nos processadores modernos, eles são uma ordem de magnitude mais rápida do que o barramento de memória.
A compactação é feita simplesmente copiando os bytes. No entanto, isso leva tempo. Quanto maior o objeto, maior a probabilidade de que o custo de copiá-lo supere as possíveis melhorias no uso do cache da CPU.
Então eles executaram um monte de benchmarks para determinar o ponto de equilíbrio. E chegou a 85.000 bytes como o ponto de corte em que a cópia não melhora mais o desempenho. Com uma exceção especial para arrays de double, eles são considerados 'grandes' quando o array tem mais de 1000 elementos. Essa é outra otimização para código de 32 bits, o alocador de heap de objeto grande tem a propriedade especial de alocar memória em endereços alinhados a 8, ao contrário do alocador geracional regular que aloca apenas alinhado a 4. Esse alinhamento é um grande problema para o dobro , ler ou escrever um duplo desalinhado é muito caro. Estranhamente, as informações esparsas da Microsoft nunca mencionam matrizes longas, não tenho certeza do que está acontecendo com isso.
Fwiw, há muita angústia do programador sobre a grande pilha de objetos não ser compactada. Isso invariavelmente é acionado quando eles escrevem programas que consomem mais da metade de todo o espaço de endereço disponível. Seguido pelo uso de uma ferramenta como um criador de perfil de memória para descobrir por que o programa falhou, embora ainda houvesse muita memória virtual não utilizada disponível. Essa ferramenta mostra os buracos no LOH, pedaços de memória não usados onde antes vivia um grande objeto, mas era coletado pelo lixo. Esse é o preço inevitável do LOH, o buraco só pode ser reutilizado por uma alocação para um objeto de tamanho igual ou menor. O verdadeiro problema é assumir que um programa deve consumir toda a memória virtual a qualquer momento.
Um problema que desaparece completamente apenas executando o código em um sistema operacional de 64 bits. Um processo de 64 bits tem 8 terabytes de espaço de endereço de memória virtual disponível, 3 ordens de magnitude a mais do que um processo de 32 bits. Você simplesmente não pode ficar sem buracos.
Resumindo, o LOH torna a execução do código mais eficiente. Ao custo de usar o espaço de endereço de memória virtual disponível menos eficiente.
ATUALIZAÇÃO, .NET 4.5.1 agora oferece suporte à compactação da propriedade LOH, GCSettings.LargeObjectHeapCompactionMode . Cuidado com as consequências, por favor.
fonte
Se o tamanho do objeto for maior do que algum valor fixado (85000 bytes no .NET 1), o CLR o colocará no Large Object Heap. Isso otimiza:
nuncararamente é compactado)fonte
A diferença essencial entre Small Object Heap (SOH) e Large Object Heap (LOH) é que a memória em SOH é compactada quando coletada, enquanto LOH não, como este artigo ilustra. Compactar objetos grandes custa muito. Semelhante aos exemplos do artigo, digamos que mover um byte na memória precisa de 2 ciclos e, em seguida, compactar um objeto de 8 MB em um computador de 2 GHz precisa de 8 ms, o que é um alto custo. Considerando que objetos grandes (matrizes na maioria dos casos) são bastante comuns na prática, suponho que essa seja a razão pela qual a Microsoft fixa objetos grandes na memória e propõe o LOH.
BTW, de acordo com este post , LOH geralmente não gera problemas de fragmento de memória.
fonte
O principal é que é improvável (e possivelmente um projeto ruim) que um processo crie muitos objetos grandes de curta duração, de modo que o CLR aloca objetos grandes em um heap separado no qual executa o GC em uma programação diferente do heap regular. http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
fonte
Não sou um especialista em CLR, mas imagino que ter um heap dedicado para objetos grandes pode evitar varreduras de GC desnecessárias dos heaps geracionais existentes. Alocar um objeto grande requer uma quantidade significativa de memória livre contígua . Para fornecer isso a partir dos "buracos" espalhados nas pilhas de gerações, você precisaria de compactações frequentes (que são feitas apenas com ciclos de GC).
fonte