Pergunta

Temos algumas operações em que estamos fazendo um grande número de grandes concatenações de cadeia, e recentemente encontrou uma exceção de memória. Infelizmente, a depuração do código não é uma opção, como isso está ocorrendo no local do cliente.

Assim, antes de olhar para uma revisão do nosso código, eu gostaria de perguntar: o que é as características de consumo de RAM de StringBuilder para grandes cadeias?

Especialmente porque eles se comparam com o tipo de cadeia de caracteres padrão. O tamanho das cordas são bem mais de 10 MB, e parece que estamos a correr para as questões em torno de 20 MB.

NOTA :. Não se trata de velocidade, mas RAM

Foi útil?

Solução

Aqui está um estudo agradável sobre concatenação de string vs alocação de memória .

Se você pode evitar concatenação, fazê-lo!

Este é um brainer não, se não o fizer tem que concatenar mas quer o seu código-fonte para uma boa aparência, use o primeiro método. Ele vai ficar otimizado como se fosse uma única cadeia.

Não use + = concatenação de cada vez. Demais mudanças estão ocorrendo por trás da cena, que não são óbvias do meu código em primeiro lugar. Eu aconselhar a preferir usar String.Concat () explicitamente com qualquer sobrecarga (2 cordas, 3 cordas, matriz de cadeia). Isto irá mostrar claramente o seu código faz sem surpresas, enquanto permitindo-se a manter um controlo sobre a eficiência.

Tente estimar o tamanho alvo de um StringBuilder.

O mais preciso você pode estimar o o tamanho necessário, a menos temporária cordas do StringBuilder terá que criar para aumentar sua interno tampão.

Não use nenhum Format () métodos quando o desempenho é um problema.

O excesso de sobrecarga está envolvido em analisar o formato, quando você poderia construir uma matriz de fora pedaços quando tudo o que você está usando são {x} substitui. Format () é bom para facilitar a leitura, mas uma das coisas para ir quando você está espremendo tudo possível fora desempenho de sua aplicação.

Outras dicas

Cada StringBuilder tempo ficar sem espaço, ele realoca um novo buffer de duas vezes o tamanho do buffer de originais, cópias dos antigos caracteres, e permite que o buffer de idade obter GC'd. É possível que você está usando apenas o suficiente (chamá-lo x) tal que 2x é maior do que a memória que você está autorizado a alocar. Você pode querer determinar um comprimento máximo de suas cordas, e passá-lo para o construtor de StringBuilder para que preallocate, e você não está à mercê da redistribuição dobrando.

Você pode estar interessado pela estrutura de dados cordas. Este artigo: : teoria e prática explica suas vantagens. Talvez haja uma implementação para .NET.

[Update, para responder ao comentário] Ele usa menos memória? Pesquisa memória no artigo, você vai encontrar algumas dicas.
Basicamente, sim, apesar da sobrecarga de estrutura, porque ele só acrescenta memória quando necessário. StringBuilder, quando esgotar tampão de idade, deve alocar uma muito maior (que já pode desperdiçar memória vazio) e deixa o antigo (que será lixo coletado, mas ainda pode usar muita memória no tempo médio).

Eu não encontrei uma implementação para .NET, mas há pelo menos uma implementação C ++ (em STL do SGI: http://www.sgi.com/tech/stl/Rope.html ). Talvez você pode aproveitar esta implementação. Note a referência de página Eu tenho um trabalho sobre o desempenho da memória.

Note que as cordas não são a cura para todos os problemas: sua utilidade depende muito como você construir seus grandes cordas, e como você usá-los. Os artigos apontam vantagens e desvantagens.

Strigbuilder é um perfeitamente boa solução para problemas de memória causados ??pela concatenação de strings.

Para responder à sua pergunta específica, StringBuilder tem uma sobrecarga de tamanho constante, em comparação com uma string normal, onde o comprimento da corda é igual ao comprimento do buffer StringBuilder atualmente alocado. O tampão poderia ser o dobro do tamanho da cadeia que os resultados, mas não mais alocações de memória será feito quando concatenando ao stringbuilder até que o buffer está cheio, por isso é realmente uma excelente solução.

Em comparação com a corda, isso é excelente.

string output = "Test";
output += ", printed on " + datePrinted.ToString();
output += ", verified by " + verificationName;
output += ", number lines: " + numberLines.ToString();

Este código tem quatro cordas que armazenados como literais no código, dois que são criados nos métodos e um de uma variável, mas ele usa seis cordas intermediárias separadas que recebem mais e mais. Se esse padrão é continuado, que irá aumentar o uso de memória a uma taxa exponencial até os pontapés GC para limpá-lo.

Eu não sei sobre o padrão exatamente memória do construtor corda, mas a corda comum não é uma opção.

Quando você usa a corda comum a cada concatenação cria um outro par de objetos string, e o foguete o consumo de memória, tornando o coletor de lixo que está sendo chamado muitas vezes.

string a = "a";

//creates object with a

a += "b"

/creates object with b, creates object with ab, assings object with ab to "a" pointer
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top