“Se você tiver muita sorte, os seus problemas de performance poderão ser facilmente resolvidos assim que ocorrerem. Mas como na maioria das vezes não é assim que ocorre, você vai ter um enorme esforço para conseguir modificar o seu código, para que alcance um nível de performance aceitável. Esta é uma péssima armadilha para se cair. E na pior das hipóteses, você irá se deparar com uma memorável frase, que às vezes finalizam um projeto: ‘Isto nunca vai funcionar, vamos ter que refazer do zero!’”.
Rico Mariani, Arquiteto, Microsoft.
Como você pôde notar, desempenho é uma questão a se preocupar durante o desenvolvimento de um projeto, e nunca após ele estar
Em geral, todos os integrantes da equipe devem estar envolvidos e comprometidos com o desempenho da aplicação: Arquitetos, Líderes dos Desenvolvedores, Desenvolvedores, Testers, Administradores ou Gerentes de Projeto e em alguns casos, a equipe deve ter um Analista de Desempenho, que será o guia principal da equipe nestas questões.
Este é um assunto muito extenso e veremos aqui apenas alguns pontos sobre esta questão que tira o sono de tanta gente.
Por onde começar?
A minha primeira sugestão é que você leia o Guia Improving .NET Application Performance and Scalability (Melhorando a Performance e a Escalabilidade de aplicações .NET). Este é um Guia de arquitetura da Microsoft que você encontra neste link: http://msdn2.microsoft.com/en-us/library/ms998534.aspx
Mesmo que você nunca tenha se preocupado com o desempenho de suas aplicações, sugiro que leia este Guia. Esta é uma literatura obrigatória para Arquitetos e Desenvolvedores .NET. A maioria das questões abordadas neste artigo foi baseada neste guia.
A quantidade de tópicos que temos sobre desempenho é enorme. E estamos falando apenas de uma fonte. Portanto, não espere achar a solução de todos os seus problemas aqui neste artigo. Repito que este é um problema sério e deve ser tratado com cuidado, e de preferência do início ao fim do projeto.
Os quatro primeiros capítulos do material citado anteriormente falam apenas das questões de Engenharia e Arquitetura que envolvem a Performance da sua aplicação. Mas nós não vamos focar nestes pontos, vamos dar uma olhada em algumas questões de desempenho que podemos usar
Garbage Collector
Quando falamos de desempenho a primeira coisa que nos vem à mente é Memória. E em .NET sabemos que memória é um assunto relacionado ao Garbage Collector. Mas você sabe o que faz o Garbage Collector?
De forma muito simplista podemos dizer que o Garbage Collector é responsável por liberar espaço de memória que não está sendo mais utilizado. Mas há muito mais sobre o Garbage Collector que você precisa saber.
O .NET Framework faz a “coleta automática do lixo” para gerenciar a memória das aplicações. Quando você usa o operador new para a criação de um objeto, um determinado espaço de memória é alocado para este objeto. Quando o Garbage Collector decide que uma quantidade suficiente de “lixo” está acumulada na memória, ele realiza uma “coleta”, para liberar um pouco deste espaço.
Este processo é inteiramente automático, mas há um número de fatores que precisamos tomar cuidado, e que podem tornar este processo mais ou menos eficiente. Para entender os princípios do Garbage Collector, você precisa entender o ciclo de vida de um objeto gerenciado.
A memória é alocada para o objeto, quando você usa o operador new. O construtor do objeto é chamado logo após a alocação da memória. O objeto é utilizado por um período de tempo. O objeto “morre” quando todas as suas referências são explicitamente setadas para null, ou quando o objeto saiu do escopo em que foi criado. A memória utilizada pelo objeto é liberada (coletada) um tempo depois. Depois que a memória é liberada, ela poderá ser utilizada por outros objetos.
Um ponto importante a considerar a respeito de desempenho do processo é o seguinte: Se há memória disponível quando você cria um novo objeto, ela é automaticamente alocada. Agora, se não há memória suficiente disponível, o Garbage Collector irá “reclamar” por memória que esteja ociosa, devido a objetos que não são mais utilizados.
Um erro muito comum é utilizar o método Collect da classe System.GC. Este método força o Garbage Collector a coletar memória. Mas, via de regra, você deve sempre evitar o uso deste método, e deixar que o próprio runtime determine qual é o momento mais apropriado para realizar a coleta.
É comum usarmos método Collect quando notamos que a memória não está sendo liberada. Porém o motivo da memória não estar sendo liberada é que estamos, inadvertidamente, “segurando” estes objetos na memória. E neste caso, o uso do método Collect não vai resolver o problema.
Gerenciamento de recursos eficiente
Como acabamos de ver, o Garbage Collector é um excelente recurso do .NET Framework. Porém é preciso cooperar com o GC, no sentido de sempre liberar os objetos que não serão mais utilizados, para que a memória que ocupam seja liberada. O acúmulo de objetos na memória, inevitavelmente irá lhe causar problemas de performance.
Entretanto, há alguns cuidados que precisam ser tomados, principalmente quando estamos falando de acesso a banco de dados. Para acessar um determinado banco de dados em nossa aplicação, geralmente utilizamos recursos como Conexões e adaptadores. Você está liberando estes recursos corretamente em sua aplicação? Dê uma olhada no código da Listagem 1.
Listagem 1. Exemplo de como NÃO liberar recursos corretamente
protected void Button1_Click(object sender, EventArgs e)
...