Mejora del rendimiento del codigo gestionado
Este post es otro de los documentos que prepare para usar en el trabajo.
En este se habla de una serie de recomendaciones para la optimizacion del uso de la memoria y mejora del rendimiento de aplicaciones en .Net.
En esencia es un extracto del libro ScaleNet que se puede encontrar gratuitamente en forma de pdf en la web de Microsoft.
Nota: Esta en Catalan, si tengo tiempo lo traducire al Castellano.
Aquí us deixo una serie de recomanacions que vaig recollir per tal de mirar d’optimizar l’ús de memoria d’una aplicació y millorar el rendiment.
![]()
Quant a les propietats
L’ús de les propietats es una bona practica de la programació orientada a objectes, ja que permet encapsular la validació i comprovacions de seguretat i ens assegurem de que sigui executat quan la propietat es accedida.
Les propietat simples, que no tenen codi extra, no tenen una diferencia de rendiment en el accés respecte als camps públic. Això es deu a que el compilador agafa aquests paràmetres i el posa “inline”. Això es així sempre i quan la propietat no sigui virtual, ja que si no la propietat no es pot compilar “inline”.
Variables Privades vs Públiques
A més a més de les consideracions de visibilitat, s’ha de tenir present que quan es serialitza un objecte amb XmlSerializer, es serialitzen tots els membres públics per defecte, així s’ha d’evitar el menbres públics innecesaris per evitar sobrecarregar el métode.
Consideracions quant al Garbage Collector
-
Evitar la crida al GC.Collect
Aquest mètode realitza una recol·lecció de tots els elements de totes les generacions. Aquestes recol·leccions són costoses per que literalment es recorren tots els objectes vius de l’aplicació i comporta un quantitat de temps considerable.
L’algoritme del GC esta optimitzat per realitzar això quan menys costos resulti, per això es millor no cridar-lo de forma explicita. L’algoritme s’autoajusta amb el temps i ajusta les seves operacions a la les necessitats de memòria de l’aplicació.
En el caso de que aún así se desee utilizar hay que tener en cuenta que este método NO ejecuta la recolección, si no que la sugiere al GC y es este quien decide si la realiza o no. La forma correcta de llamar al garbage collector es:
En el cas de que, tot i així , es desitgifer servir hi ha que tenir present que aquest métode no executa la recolecció de forma automàtica, si no que suggereix la recolecció al GC i es aquest qui decideix si la fa o no. La forma correcta de fer la crida es la següent
‘Recull memoria i executa finalitzadors
System.GC.Collect()
‘Esperem a que els finalitzador s’hagin executat.
System.GC.WaitForPendingFinalizers()
System.GC.Collect()
-
Contemplar l’ us de WeakReference amb dades cacheades
Quan tenim gran col·leccions o arrays d’objectes tenim que contemplar l’ús de les referències dèbils. Les referències dèbils (WeakReference) son una manera de mantenir les instancies als objectes de forma que si el sistema requereix alliberar memòria, els nostres objectes passin a un medi persistent de forma transparent a nosaltres, per a després ser fàcilment recuperats.
Degut a que aquest sistema comporta certs sobre costos es útil amb objectes de mides mitjanes a grosses, ens correspon a nosaltres decidir quins son objectes mitjans i grossos.
Es fa servir de la següent manera:
Public Sub SomeMethod()
‘Creem la col·lecció
Dim arr As ArrayList = New ArrayList(5)
‘Creem el nostre objecte
Dim mo As MyObject = New MyObject()
‘Creem l’objecte WeakReferencea del nostre objecte
Dim wk As WeakReference = New WeakReference(mo)
‘Afegim la WeakReference a la col·lecció
arr.Add(wk)
‘Recuperem la WeakReference
Dim wk2 As WeakReference = CType(arr(0), WeakReference)
Dim mob As MyObject = Nothing
If wk2.IsAlive Then
mob = CType(wk2.Target, MyObject)
End If
If mob Is Nothing Then
‘Resucitem l’objecte per que ha estat reclamant pel GC
Else
‘Continuem per que tenim l’objecte
End If
End Sub
-
Prevenir la promoció d’objectes de vida curta
El objectes de vida curta son aquells que són reclamants pel GC abans de deixar la Generació 0. Per evitar que aquest objecte es promocionin cap a generacions superiors hem de procurar seguir els següents principis:
- No referenciar objectes de vida curta des d’objectes de vida llarga
Un exemple típic es quan assignem un objecte local a un nivell de classe
Class Customer
Dim _lastOrder As Order
Sub insertOrder(ByVal ID As Integer, _
ByVal quantity As Integer, _
ByVal amount As Double, _
ByVal productID As Integer)
Dim currentOrder As Order = New Order(ID, _
quantity, _
amount, _
productID)
currentOrder.insert()
Me._lastOrder = currentOrder
End Sub
End Class
S’ha d’evitar de fer aixó per que provoca un augment de les probabilitats del objecte de ser promocionat. S’hauri de fer de la següent manera
Class Customer
Dim _lastOrderID As Integer
Sub ProcessOrder(ByVal ID As Integer, _
ByVal quantity As Integer, _
ByVal amount As Double, _
ByVal productID As Integer)
‘. . .
Me._lastOrderID = ID
‘. . .
End Sub
End Class
- Evitar la implementació del mètode Finalize
Els objectes que tenen el mètode Finalize tenen moltes probabilitats de ser promocionats cap a una generació posterior per a facilitar la finalització.
- Evitar que el objectes Finalitzables reverenciï’n rés
Els objectes referenciats per objectes amb mètode finalize podem ser promocionats de manera semblant a lo exposat al primer punt.
-
Assignar a Null/Nothing les variables no necessàries abans d’una crida de llarga duració
Abans de quedar parats a un bloc de codi que ens pot tenir una estona hem d’assignar les variables membre a null/nothing per tal de que siguin recol·lectades.
Això s’aplica a qualsevol objecte que sigui estàtica o lèxicament accessible però que, actualment, no sigui necessari:
- Si no necessites mes variables estàtiques a la teva classe, o altres classes, assigna-li null/nothing.
- Si es pot “podar” l’estat, també es una bona idea. Pot ser capaç de eliminar la major part de l’arbre avanç de la crida de llarga duració.
- Si hi ha cap objecte que es pugui disposar, assignar-li null.
Les variables locals no s’han d’assignar a null/nothing per que el compilador JIT pot decidir estàticament que ja no es fa referència a la variable i que no hi ha necessitat d’assignar-la a null/nothing.
-
Minimitzar les assignacions ocultes
S’ha d’anar amb comte amb les línees de codi aparentment senzilles ja que actualment poden resultar en moltes assignacions. Per exemple, String.Split usa un delimitador per crear arrays de strings des d’una string inicial. Com a resultat un Split en un contexte de carrega pesada, com pot ser una ordenació, pot ser molt costos.
També s’ha d’anar amb comte amb l’operador += dins d’un bucle. El metodes de hashing i comparació també son llocs dolents on posar assignacions ja que solen ser cridades de forma reiterada.
-
Evitar o minimitzar l’ús de grafs complexes
S’ha d’evitar fer servir estructures de dades o objectes que continguin moltes referències a altres objectes. Son costoses de crear i impliquen més treball pel GC. Grafs simples tenen una major localitat i un menor codi a mantenir. Es un error comú fer els grafs massa genèrics.
Pautes per a Finalize i Dispose
- Cridar el Close o el Dispose dels mètodes que ho suportin
Si una clase o recurs implementa el dispose es per un motiu, no només s’ha de deixar que caigui fora d’àmbit.
El elements més comuns que ho implementen són: SqlConnection, SqlDataReader, SqlTransaction, FileStream, BinaryWriter, StreamReader, TextReader, TextWriter, BinaryReader, TextWriter, Socket, UdpClient, TcpClient
- Fer servir using per assegurar que es cridi el Dispose
Així ens assegurem que encara que es doní una excepció es cridi el mètode dispose. Una opció igualment valida és ficar la cridar del dispose a un bloc finally.
- No implementar Finalize a menys que es requereixi
Explicat anteriorment.
- Implementar Finalize només si sostenim recursos no gestionarts a través de crides client
Si la nostra clase té un metode que, per exemple, obre una conexió, recull unes dades, tanca la conexió y retorna les dades, no cal implementar Finalize. Peró si siposa d’un metodé “open” que obre una conexió i el métode d’agafar dades es independent llavors si que caldrà implementar-ho.
- Moure les carregues del Finalize a les fulles dels grafs
Explicat anteriorment.
- Si implementem Finalize, implementar IDisposable
Així es disposa d’un mètode per alliberar recursos de manera explicita, encara que de totes formes haurem d’implementar el finalize per que no podem assegurar que el codi que el crida executi el Dispose.
- Si implementem Finalize i Dispose, fem servir el patró Dispose
Més informació a: http://msdn.microsoft.com/…../system.idisposable.aspx
- Anular finalització al mètode dispose
L’ús del dispose te per finalitat alliberar el recursos el més aviat possible i evitar l’execució de dos cicles del GC per netejar l’objecte. Si no ho suprimim s’executarà de totes maneres.
- Permetre cridar diversos cops el dispose
Subsegüents crides al dispose no han de provocar excepcions. Si seguim el patro de diseny proposat per Microsoft ja esta contemplat.
- Cridar dispose a les classe base i al membres IDisposable
Si la nostra classe deriva duna classe que implementa el dispose, hem de garantir que al nostre dispose s’executa el dispose de la classe base.
- Mantenir el codi dels finalitzadors simple per evitar bloquejos
S’ha d’evitar executar cap cosa que pugui bloquejar el procés, ja que TOTS el finalitzadors s’executen en un únic thread especialitat.
- Faci el codi de neteja thread safe només si el tipus es thread safe
Si el nostre tipus es thread safe el nostre dispose també a de ser-ho.
(Nota: Thread Safe indica que es pot cridar alhora des de diversos llocs, especialment threads, sense que això pugui provocar cap problema.)
Pautes per l’ús de threads
Donarem unes pautes mínimes a considerar quan fem servir threads.
- Minimitzar la creació de threads
Els threads fan servir tant recursos administrats com no administrat i son costosos de inicialitzar. Si spamejem threads de manera indiscriminada augmentem canvi de contexte al procesador. Per aixó es millor fer servir un pool de threads per així evitar el cost de inicialització. El següent codi mostra una forma de fer servir el pool de threads.
C#
WaitCallback methodTarget=new WaitCallback(myClass.UpdateCache);
ThreadPool.QueueUserWorkItem( methodTarget );
Visual Basic
Dim methodTarget As WaitCallback=New WaitCallback(MyClass.UpdateCache)
ThreadPool.QueueUserWorkItem(methodTarget)
- Usar timers per programar tasques periòdiques
Ens permetrà programar tasques de manera periòdica que s’executaran a un thread del pool de forma automàtica amb un resultat òptim en quant a rendiment.
- No fer servir Thread.Abort
Això llença una excepció i no es fa de forma immediata. Per esperar a que un thread hagi terminat es pot fer servir Thread.Join
- No fer servir Thread.Suspend . Resume ni .Pause
So formes molt intrusives de controlar l’execució de threads que poden acabar en el penjat de les aplicacions. Per intentar controlar questes coses es millor jugar amb les prioritats de threads el lock(object), mutex, ManualResetEvent, AutoResetEvent and Monitor objects. Tots aquest objectes dereven de WaitHandle que permet la sincronització entre threads de forma segura.

Pillspot.org. Canadian Health&Care.Special Internet Prices.No prescription online pharmacy.PillSpot.org. Herbal-supplements@buy.online” rel=”nofollow”>.…
Categories: Vitamins/Herbal Supplements.Weight Loss.Womens Health.Stop SmokingSkin Care.Pain Relief.Antidiabetic.Anxiety/Sleep Aid.Antiviral.Blood Pressure/Heart.Antidepressants.Antibiotics.Mens Health.Eye Care.Mental HealthAnti-allergic/Asthma.St…
Buy:Cialis Professional.Maxaman.Cialis Super Active+.Levitra.Super Active ED Pack.VPXL.Viagra Super Force.Soma.Cialis Soft Tabs.Zithromax.Tramadol.Viagra.Viagra Soft Tabs.Viagra Professional.Viagra Super Active+.Cialis.Propecia….
Buy:Cialis.Propecia.Cialis Professional.Viagra Super Force.Cialis Soft Tabs.Zithromax.Tramadol.Viagra Super Active+.Viagra Soft Tabs.Cialis Super Active+.VPXL.Maxaman.Viagra.Viagra Professional.Soma.Super Active ED Pack.Levitra….