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.