
Os tipos por
referência são especialmente úteis. Eles são responsáveis por guardar tipos
mais complexos como classes. Estes tipos normalmente ocupam grande espaço em
memória. Quando um tipo por referência é utilizado como parâmetro para um
método, este parâmetro aponta para o tipo por referência. E quando um tipo por
referência é atribuído por outro, existe um apontamento interno, diferentemente
do tipo por valor. Isto é de grande valia para objetos pesados.
Os tipos por referência mais fundamentais
são:
- System.Object
- System.String
- System.Text.StringBuilder
- System.Array
- System.IO.Stream
- System.Exception
Por que utilizar StringBuilder a string?
As strings são
classes prontas do .NET para tratamento de arrays de caracteres. Enquanto um
char[] utiliza a classe System.Array, um string utiliza a classe System.String.
A classe System.String se especializa no tratamento de array de caracteres
trazendo uma série de benefícios na sua manipulação.
As strings em
.NET e em outras linguagens apresentam uma limitação: as strings são imutáveis.
Isto significa que é impossível alterar uma string em .NET. Esta afirmativa é
estranha por que é comum a alteração de string, porém internamente a CLR
realiza uma manobra para que isto funcione corretamente. Quando uma string é
definida, uma posição de memória é alocada na stack para apontar para um
endereço da heap que conterá a string. Se esta string for alterada, uma nova entrada
será feita na stack e outra cópia será feita na heap. E pelo menos o .NET apaga
o endereço de memória da stack que contém a antiga string. Desta forma na
próxima passagem do Garbage Collector, todas as strings antigas serão
excluídas. Veja o código – comentado – a seguir que mostra este problema:
public static void Main()
{
// System.Int32 ocupa 4 Bytes somente na stack
int
valor1 = 300;
int valor2 =
600;
int
valor3 = 900;
string
valor;
// System.String ocupa o equivalente a um System.IntPtr na stack.
//Este valor varia de acordo com a plataforma
/* Como
este valor não está instanciado, apenas ocupa a stack, e não aponta para a heap
*/
valor = "Esta
string é um teste";
// Um novo espaço (System.IntPtr) é ocupado na stack
/* O
espaço antigo não é anulado (embora já estivesse)*/
/* A heap
guarda o tamanho da string mais outras partes da classe System.String*/
valor += "\nO
valor 1 é de " + valor1;
// Um novo espaço (System.IntPtr) é ocupado na stack
/* O
espaço antigo não é anulado*/
/* A heap
guarda o tamanho da string mais outras partes da classe System.String*/
valor += "\nO
valor 2 é de " + valor2;
// Um novo espaço (System.IntPtr) é ocupado na stack
/* O
espaço antigo não é anulado*/
/* A heap
guarda o tamanho da string mais outras partes da classe System.String*/
valor += "\nO
valor 3 é de " + valor3;
// Um novo espaço (System.IntPtr) é ocupado na stack
/* O
espaço antigo não é anulado*/
/* A heap
guarda o tamanho da string mais outras partes da classe System.String*/
//
Imprime na tela o valor da string
Console.Write(valor);
}
A aplicação citada gasta:
- 3 System.Int32
- 4 Bytes cada
- 12 Bytes da stack
- Gastos corretamente
- 5 System.IntPrt
- O valor varia de acordo com a plataforma
- Gasta no mínimo 5 bytes da stack
- Os 5 System.IntPrt representam indiretamente a mesma System.String
- 5 System.String
Agora, tendo o problema bem claro, então
qual é a solução? O .NET oferece um objeto que resolve esta questão:
System.Text.StringBuilder. Diferentemente da string, ele tem a função de montar
strings e, apenas, uma string é criada na memória após uma manipulação de
string. Veja o código que segue, ele resolve o problema apresentado no código
anterior:
public static
void Main()
{
// System.Int32 ocupa 4 Bytes somente na stack
int
valor1 = 300;
int
valor2 = 600;
int
valor3 = 900;
// System.Text.StringBuilder equivale
a um System.IntPtr na stack. Este valor varia de acordo com a plataforma
System.Text.StringBuilder sb = new
StringBuilder();
sb.Append("Esta string é um teste");
sb.Append("\nO
valor 1 é de " + valor1);
sb.Append("\nO
valor 2 é de " + valor2);
sb.Append("\nO
valor 3 é de " + valor3);
// Um novo espaço (System.IntPtr) é ocupado na stack
/* A heap
guarda o tamanho da string mais outras partes da classe System.String*/
string
valor = sb.ToString();
//
Imprime na tela o valor da string
Console.Write(valor);
}
Desta forma, o resumo dos gastos são:
- 3 System.Int32
- 4 Bytes cada
- 12 Bytes da stack
- Gastos corretamente
- 2 System.IntPtr
- O valor varia de acordo com a plataforma
- 1 para apontar para um System.String, criado corretamente
- 1 para apontar para um System.Text.StringBuilder, criado corretamente
- 1 System.String
- 1 System.Text.StringBuilder
Nenhum comentário:
Postar um comentário