Programming Languages Hacks

Importanti regole per linguaggi di programmazione rilevanti come Java, C, C++, C#…

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

Archive for the '.net' Category

Perché passare da Svn a Git

Posted by Ricibald on 30th August 2011

Come al solito… articolo condensato per non perdere tempo…!

Perché scegliere Git rispetto agli altri controlli versione come Svn, Cvs, …? Di seguito un elenco delle cose che Git consente in più rispetto agli altri sistemi:

  1. git è distribuito: ogni client non ottiene l’ultima versione disponibile (come in Svn) ma un clone dell’intero repository con tutto lo storico. Questo abilita un uso completo offline di tutte le funzionalità (commit, diff, log, branch, merge, annotation) in modo istantaneo. Inoltre il sistema non avrà un Single Point of Failure poiché ogni client avrà il full backup del progetto. Infine si può articolare una struttura di workflow in cui si mantengono dei repository separati con diversi permessi di lettura/scrittura che vengono integrati in un workflow “gold” (si veda questo articolo) [in TFS strutturare in questo modo è possibile grazie a un uso corretto dei permessi e delle policy].
  2. branch semplici: creare un branch ed eseguire lo switch a un branch sono operazioni che impiegano qualcosa come 0.1 secondi. Tale velocità cambia l’aspetto psicologico del branch: diventa un’operazione comune per qualunque cosa su cui si lavora: ogni feature, idea, bugfix, senza essere online con la possibilità di annullare un branch e cambiare contesto quasi in modo istantaneo. Il merge inoltre è a 3 vie e riduce al minimo le probabilità di conflitti.
  3. commit organizzate per feature: a differenza di altri sistemi come Svn, in Git i file locali non vengono inviati direttamente nel repository ma passano prima per una staging area (o index) che consente di specificare nel dettaglio quali file (e quali porzioni di file) si andranno a committare, in modo da risolvere il problema della “copia di lavoro intricata” e mantenere ogni commit un evento con il preciso scopo di riportare i file modificati impattati dopo aver implementato una determinata feature. Questa separazione consente di eseguire ad esempio il merge solo di determinate feature, lasciandone indietro altre.
    Infatti Git viene definito un “change control” invece di un “version control”: invece di presentare il progetto linearmente (mentalità dell’”undo”) Git vede solo un manipolo di commit pronti per essere rimescolati o amalgamati insieme
  4. utile a te: spesso si sceglie di non usare Git poiché non si fa parte di un team numeroso. In realtà Git aiuta te, non il tuo team: il branch locale, il context switching, le commit come feature, aiutano l’individuo, non il team. Velocità e backup sono sempre una buona cosa, sia in team che non.
Ottimi articoli:

Posted in .net | No Comments »

Adapt/convert Microsoft Ajax events to JQuery

Posted by Ricibald on 22nd July 2011

It’s very useful to express everything in JQuery instead of ASP.NET AJAX events system: in this way we can use a lot of useful JQuery controls.

To achieve this just add this snippet of javascript code:

<script type="text/javascript">
	Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequest);
	Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequest);
	function BeginRequest(sender, args) {
		jQuery.event.trigger('ajaxSend');
	}
	function EndRequest(sender, args) {
		jQuery.event.trigger('ajaxComplete');
	}
</script>

In this way you can capture standard JQuery event to obtain for example a modal progress feedback both in case of JQuery ajax POST and in case of ASP.NET UpdatePanel events:

<script type="text/javascript">
	$(document).bind("ajaxSend", function () {
		$("#loadingAjax").dialog({ modal: true });
	}).bind("ajaxComplete", function () {
		$("#loadingAjax").dialog("close");
	});
</script>

Posted in asp.net, javascript, jQuery | No Comments »

jQuery: HTTP POST with specific <input type=”submit”>

Posted by Ricibald on 19th April 2011

jQuery allows only to do a global form submit using

$("form").submit()

This method doesn’t allow to do a specific form submit when multiple <input type=”submit”> exists, like in many ASP.NET sites, where there are a single form with many buttons.

To achieve this and obtain an ASP.NET POSTBACK behavior simply use this snippet of jQuery code that builds a “submit simulation from input”:

// simulate submit from button "myButton"
var input = $("<input>").attr("type", "hidden").attr("name", $('#myButton').attr("name")).val("");
$('form').append($(input));
$('form').submit();

Posted in .net, javascript, jQuery | No Comments »

Pattern Flyweight in Pratica: Predisporre un’Applicazione per il Precache

Posted by Ricibald on 18th January 2010

Il pattern Flyweight consente di riutilizzare gli oggetti in modo da poter evitare allocazioni. Questo risulta utile se:

  1. gli oggetti da creare richiedono molta memoria
  2. gli oggetti da creare sono molti
  3. gli oggetti da creare sono costosi da creare (e distruggere) dal punto di vista computazionale
  4. i vincoli impongono un sistema che non abbia cali improvvisi di performance, derivanti ad esempio dall’inizializzazione pesante di un oggetto
  5. i vincoli impongono un utilizzo molto attento delle risorse
Facciamo un esempio pratico di ognuno di questi punti:
  1. un’animazione può avere tante caratteristiche ingenti da memorizzare come accelerazione, direzione, …
  2. un word processor utilizza migliaia di caratteri con le stesse info su font, dimensione, colore, …
  3. un’immagine: il caricamento richiede ogni volta l’accesso al filesystem
  4. un videogioco deve avere fps costanti e non avere improvvisi picchi negativi di 10fps solo perché si alloca una risorsa
  5. un dispositivo mobile come il Nokia o l’iPhone
La parte critica a mio parere non è implementare il pattern direttamente: con un po’ di sforzo si riesce! Il problema sta nell’adattare un progetto non pensato per questo pattern, in questo caso l’implementazione non diventa affatto banale!
Facciamo un esempio pratico: ho un’applicazione per iPhone che deve gestire delle biglie che rimbalzano di numero crescente. All’inizio le prestazioni risultano buone ma poi iniziano a degradare evidenziando due problemi:
  • la memoria inizia a non essere sufficiente per le info necessarie
  • l’allocazione/deallocazione causa picchi negativi di fps, ora (più) evidenti a causa dello stesso degrado delle performance generali
Per questo vorremmo gestire tutti gli aspetti comuni a ogni singola biglia attraverso il pattern Flyweight. Vorremmo quindi gestire:
  • lo stato intrinseco della biglia nel flyweight
    • posizione, comportamento specifico della biglia
  • lo stato estrinseco della biglia nella nostra app, che lo passa al flyweight
    • immagine, colore, dimensione, comportamenti comuni di animazioni
Facile a dirsi, ma se non abbiamo pensato la app in questo modo ci troveremo tanti problemi. Infatti al momento di creare una biglia prima:
  • veniva creata e associata l’immagine corrispondente
  • veniva aggiunta l’immagine alla scena corrente assegnando uno z-index
  • veniva assegnato un comportamento della biglia: quanto rimbalzare, se esplode, …
Capire effettivamente cosa estrarre da tutto questo diventa una sfida a volte irrisolvibile, anche a causa dei vincoli tecnologici a cui ci sottopongono i framework stessi, che non prevedono il riuso delle strutture.
Per questo, a parte la teoria del pattern, bisognerebbe:

capire come predisporre una applicazione per fare uso di un precaching in modo da abilitare il pattern con poco sforzo

Rivediamo quindi l’obiettivo: non vogliamo applicare alla lettera il pattern Flyweight (difficile da adattare al nostro contesto) ma vogliamo evitare allocazioni inutili. Una strategia sta nel riutilizzare le stesse istanze ogni volta che queste non sono più utili. Infatti se una biglia esce dal gioco la strategia comune è deallocare la biglia stessa e allocarne una nuova quando necessario. Invece decidiamo di riutilizzare le stesse istanze quando escono dal campo visivo: ci sarà l’illusione di distruggere la biglia, ma non sarà così! In questo modo possiamo ottenere due vantaggi:
  • l’allocazione e deallocazione, che causavano picchi negativi di fps sono presenti un’unica volta
  • creiamo le premesse per un precaching di ad es. 40 biglie, utile per impedire completamente il problema di picchi negativi di fps
Tornando al problema precedente, quando costruiamo una app non sapremo se questo servirà o meno, ma nel dubbio la cosa conveniente è senza dubbio:

dividere inizializzazione estrinseca da inizializzazione intrinseca in modo da poter riutilizzare l’inizializzazione quando richiesto

Il trucco è quindi proprio questo: nella creazione degli oggetti dovremmo inizializzare solo quello che non cambia nella biglia come l’immagine il colore, … Dopo aver creato gli oggetti passiamo quindi per una seconda fase di inizializzazione che imposta lo stato intrinseco della biglia stessa come la posizione e il comportamento. Questo lo facciamo a priori!! Un piccolo sforzo, ma in fondo ben gestibile. Se un giorno servirà questo ci verrà di aiuto!
Immaginiamo che sia venuto quel giorno! Basta creare una FlyweightFactory che consente il seguente flusso:

  • allo startup la FlyweightFactory crea ad es. 40 biglie e le mantiene in un proprio pool di precaching
  • quando alla app serve una biglia richiede un’istanza disponibile alla FlyweightFactory
  • la FlyweightFactory restituirà un’istanza dal pool con lo stato intrinseco correttamente inizializzato
  • quando la biglia non viene più referenziata nella nostra app ma esiste solo nella FlyweightFactory deve esistere una strategia per marcare l’istanza come disponibile nel pool (es. un meccanismo di notifica a eventi)

Fare questo a fronte della divisione tra allocazione/inizializzazione è un gioco da ragazzi!

A questo punto rimane solo il problema dell’allocazione dello stato estrinseco, che viene ridondata per ogni biglia. Per questo risulta quindi necessario aggiungere come parametro nell’allocazione (creazione) delle biglie lo stato estrinseco stesso, che viene creato un’unica volta dalla factory. In questo modo risolviamo il problema finale.

Il flusso di inizializzazione diventa quindi:

  • allo startup viene inizializzato lo stato estrinseco
  • la FlyweightFactory alloca un pool di 40 biglie passando lo stato estrinseco
  • le singole istanze memorizzano il riferimento allo stato estrinseco
  • la app richiede un’istanza alla FlyweightFactory
  • la FlyweightFactory inizializza un’istanza disponibile dal pool e la restituisce. Rimangono quindi 39 biglie nel pool
  • la app usa la biglia. Quando non serve più la rimuove dalla app
  • la app lancia un evento di avvenuta rimozione della biglia
  • la FlyweightFactory riceve l’evento e aggiunge la biglia nel pool delle istanze disponibili. Rimangono quindi 40 biglie nel pool
Concludendo abbiamo leggermente modificato il pattern Flyweight per adattarlo a contesti reali: il pattern infatti prevede che le singole operazioni portino con sé lo stato estrinseco su cui lavorano mentre la nostra soluzione prevede un’allocazione che assegni lo stato estrinseco e le singole operazioni che lo usano come se lo avessero creato loro. Questo si sposa bene con il refactoring necessario per applicare il pattern, che altrimenti richiederebbe un ripensamento globale dell’applicazione.

Posted in .net, performance | 1 Comment »

Weak Delegate: gestire Eventi senza causare Memory Leak

Posted by Ricibald on 14th December 2009

Uno dei motivi principali di memory leak è il riferimento circolare tra oggetti, come già osservato nel precedente post.

Un’istanza particolare di questo problema si trova nella gestione degli eventi. Consideriamo questo scenario: la window2 (subscriber) registra il proprio handler all’evento TextChanged della window1 padre (publisher). Ci aspetteremmo che la window2 venga deallocata quando chiusa ma questo non succederà poiché la window1 mantiene uno strong reference verso la window2 mediante la registrazione dell’handler.

La window1 in realtà detiene l’ownership di window2 poiché è la finestra padre, ma questa relazione viene già mantenuta mediante la lista Children, non tramite l’handler.
Il punto è quindi che, mentre la cancellazione della lista viene gestita dallo stesso framework grafico che quindi garantisce uno stato corretto per la deallocazione, risulta invece nostra responsabilità gestire la deferenziazione di altri strong reference mantenuti. Questo discorso non si applica quindi solo agli event handler ma anche a data binding e a command, i quali internamente mantengono strong reference.

Una soluzione consiste nel deregistrare gli handler (o databinding o command) al momento della close della window2, ma risulta una soluzione fragile: si presta facilmente a errori durante lo sviluppo.

Una soluzione migliore sarebbe registrare un “weak delegate”: in questo modo il publisher non vincolerebbe il ciclo di vita dei subscriber.

Ma come fare a creare un weak delegate? Il trucco è in sostanza questo: dobbiamo rimpiazzare il “delegate originale” con un suo “delegate proxy”, il quale invoca il delegate originale se il target del delegato non è stato deallocato. Per fare questo quindi il delegate proxy deve mantenere un weak reference verso il delegate originale. La soluzione concettuale è espressa in queste poche righe di codice:

public static EventHandler ToWeak(EventHandler eventHandler)
{
    var weakAction = new WeakReference(eventHandler);
    var handler = new EventHandler((sender, e) =>
    {
        var target = weakAction.Target as EventHandler;
        if (target != null) target(sender, e);
    });
    return handler;
}

Combinando questo con gli extension methods possiamo quindi ottenere un fantastico metodo “ToWeak” che trasforma un delegate standard in un “weak delegate”:

    public static class ExtensionMethods
    {
        public static EventHandler ToWeak(this EventHandler eventHandler)
        {
            var weakAction = new WeakReference(eventHandler);
            var handler = new EventHandler((sender, e) =>
            {
                var target = weakAction.Target as EventHandler;
                if (target != null) target(sender, e);
            });
            return handler;
        }

        public static EventHandler<TEventArgs> ToWeak<TEventArgs>(this EventHandler<TEventArgs> eventHandler)
            where TEventArgs : System.EventArgs
        {
            var weakAction = new WeakReference(eventHandler);
            var handler = new EventHandler<TEventArgs>((sender, e) =>
            {
                var target = weakAction.Target as EventHandler<TEventArgs>;
                if (target != null) target(sender, e);
            });
            return handler;
        }
    }

    class Subscriber
    {
        public void Handler(object sender, EventArgs e)
        {
            Console.WriteLine("Handler called");
        }

        ~Subscriber()
        {
            Console.WriteLine("Subscriber Cleaned");
        }
    }

    class Publisher
    {
        public event EventHandler Click;
        public string Id { get; private set; }

        public Publisher(string id)
        {
            this.Id = id;
        }

        ~Publisher()
        {
            Console.WriteLine("Publisher Cleaned");
        }

        public void OnClick()
        {
            if(Click != null)
            {
                Click(this, new EventArgs());
            }
        }
    }

    class Program
    {
        public static void Main()
        {
            Console.WriteLine("+ TEST 1: WITHOUT WakeEventHandler");
            RunTestWithWakeFlag(false);

            Console.WriteLine("+ TEST 2: WITH WakeEventHandler");
            RunTestWithWakeFlag(true);

            Console.ReadLine();
        }

        public static void RunTestWithWakeFlag(bool isWake)
        {
            waitAndWrite("+--- ***Subscriber Creation***");
            var subscriber = new Subscriber();

            waitAndWrite("+------ Holding the Subscriber's Handler");
            EventHandler h = createEventHandler(subscriber.Handler, isWake);

            waitAndWrite("+------ Raising Subscriber Event");
            h(null, EventArgs.Empty);

            waitAndWrite("+------ Subscriber not yet used by application. GC called\r\n+------ [!!!LEAK HERE IF NOT WEAK!!!] (CLASSES MANTAINES IN LIFE ALL CLASSES'S DELEGATE)");
            subscriber = null;
            garbageCollect();

            waitAndWrite("+------ Raising Subscriber Event Again");
            h(null, EventArgs.Empty);

            waitAndWrite("+------ Handler not yet used by application. GC called");
            h = null;
            garbageCollect();

            waitAndWrite("+--- ***Publisher Creation (12345)***");
            var publisher12345 = new Publisher("12345");

            waitAndWrite("+------ Publisher Registration Anonymous Event");
            publisher12345.Click +=
                createEventHandler((s, a) => Console.WriteLine(String.Format("Anonymous Subscriber Called (subscribed to {0})", publisher12345.Id)), isWake);

            waitAndWrite("+------ Raising Publisher's Events");
            publisher12345.OnClick();

            waitAndWrite("+------ Publisher not yet used by application. GC called");
            publisher12345 = null;
            garbageCollect();

            waitAndWrite("+--- ***Publisher Creation (67890)***");
            var publisher67890 = new Publisher("67890");

            waitAndWrite("+------ Publisher Registration Event in other Class");
            var subscriber67890 = new Subscriber();
            publisher67890.Click += createEventHandler(subscriber67890.Handler, isWake);

            waitAndWrite("+------ Raising Publisher's Events");
            publisher67890.OnClick();

            waitAndWrite("+------ Subscriber not yet used by application. GC called\r\n+------ [!!!LEAK HERE IF NOT WEAK!!!] (PUBLISHER MANTAINES IN LIFE ALL ITS SUBSCRIBERS)");
            subscriber67890 = null;
            garbageCollect();

            waitAndWrite("+------ Publisher not yet used by application. GC called");
            publisher67890 = null;
            garbageCollect();

            waitAndWrite("+--- End");
        }

        private static void waitAndWrite(string text)
        {
            Console.ReadLine();
            Console.WriteLine(text);
        }

        private static void garbageCollect()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }

        private static EventHandler createEventHandler(EventHandler action, bool isWake)
        {
            return isWake ? action.ToWeak() : action;
        }
    }

L’output prodotto a video dai test è il seguente:

+ TEST 1: WITHOUT WakeEventHandler

+--- ***Subscriber Creation***

+------ Holding the Subscriber's Handler

+------ Raising Subscriber Event
Handler called

+------ Subscriber not yet used by application. GC called
+------ [!!!LEAK HERE IF NOT WEAK!!!] (CLASSES MANTAINES IN LIFE ALL CLASSES'S D
ELEGATE)

+------ Raising Subscriber Event Again
Handler called

+------ Handler not yet used by application. GC called
Subscriber Cleaned

+--- ***Publisher Creation (12345)***

+------ Publisher Registration Anonymous Event

+------ Raising Publisher's Events
Anonymous Subscriber Called (subscribed to 12345)

+------ Publisher not yet used by application. GC called
Publisher Cleaned

+--- ***Publisher Creation (67890)***

+------ Publisher Registration Event in other Class

+------ Raising Publisher's Events
Handler called

+------ Subscriber not yet used by application. GC called
+------ [!!!LEAK HERE IF NOT WEAK!!!] (PUBLISHER MANTAINES IN LIFE ALL ITS SUBSC
RIBERS)

+------ Publisher not yet used by application. GC called
Subscriber Cleaned
Publisher Cleaned

+--- End

+ TEST 2: WITH WakeEventHandler

+--- ***Subscriber Creation***

+------ Holding the Subscriber's Handler

+------ Raising Subscriber Event
Handler called

+------ Subscriber not yet used by application. GC called
+------ [!!!LEAK HERE IF NOT WEAK!!!] (CLASSES MANTAINES IN LIFE ALL CLASSES'S D
ELEGATE)
Subscriber Cleaned

+------ Raising Subscriber Event Again

+------ Handler not yet used by application. GC called
WeakEventHandler Cleaned

+--- ***Publisher Creation (12345)***

+------ Publisher Registration Anonymous Event

+------ Raising Publisher's Events
Anonymous Subscriber Called (subscribed to 12345)

+------ Publisher not yet used by application. GC called
WeakEventHandler Cleaned
Publisher Cleaned

+--- ***Publisher Creation (67890)***

+------ Publisher Registration Event in other Class

+------ Raising Publisher's Events
Handler called

+------ Subscriber not yet used by application. GC called
+------ [!!!LEAK HERE IF NOT WEAK!!!] (PUBLISHER MANTAINES IN LIFE ALL ITS SUBSC
RIBERS)
Subscriber Cleaned

+------ Publisher not yet used by application. GC called
WeakEventHandler Cleaned
Publisher Cleaned

+--- End

Si noti un aspetto importante: se abbiamo 99 subscriber, la chiusura delle 99 window dei subscriber non deregistra i 99 handler dell’evento nel publisher, semplicemente i 99 handler ora punteranno a un reference ormai deallocato, ma continueranno a esistere. Perciò un leggerissimo memory leak permane e a livello computazionale il sistema continuerà ancora a gestire 99 handler. Ma la struttura dei subscriber viene deallocata correttamente ed è ciò che conta, poiché sarà il memory leak “vero” da gestire.

Infine bisogna notare che l’implementazione può essere notevolmente raffinata e resa generica come indicato nell’articolo di Greg Schechter applicando reflection o lambda expression, ma questo può causare rallentamenti di performance che secondo me devono essere giustificati dalla necessità effettiva di rendere l’approccio generico.

Posted in .net, performance | 2 Comments »

Memory Leak con Garbage Collection: WeakReference

Posted by Ricibald on 27th November 2009

Come tutti sapete, la GC è una modalità automatica di gestione della memoria tramite cui vengono liberate porzioni non più referenziate. In questo modo il programmatore non si deve più preoccupare di deallocare esplicitamente gli oggetti e si evitano i tipici problemi legati alla gestione della memoria (dangling pointer e memory leak).

Se per memory leak intendiamo il mancato rilascio di memoria non più referenziata allora il GC effettivamente evita qualunque memory leak, ma se per memory leak intendiamo il mancato rilascio di memoria non più utilizzata, allora la GC non è sufficiente: non può conoscere le nostre intenzioni!!

Ora mi spiegherò meglio, ma è necessario prima notare una cosa importante: il problema che descriverò è generale per la GC, ma non significa che implementazioni più raffinate non abbiano risolto il problema. Infatti implementazioni C# o Java non prevedono questo problema, ma si noti anche che, per quanto raffinata sia l’implementazione della GC, questi errori non potranno mai essere completamente impediti, quindi è necessario un approccio consapevole alle tematiche.

Dunque mi spiego meglio: immaginiamo di avere un oggetto che rappresenta la struttura di una società. Avremo quindi una lista di dipendenti, di cui ognuno avrà un superiore (se esiste) e avrà dei dipendenti da coordinare (se non si trova all’ultimo gradino). Di seguito riporto un esempio di istanza dopo il suo utilizzo:

Come osserviamo l’applicazione dopo aver utilizzato la struttura, ora ha ormai perso il riferimento a qualunque dipendente. Sarebbe lecito aspettarsi che gli oggetti vengano deallocati in quanto non più utilizzati. Infatti “Riccardo” non viene più usato da nessuno e quindi deve essere deallocato sé stesso e tutti i dipendenti che referenzia in quanto a loro volta perdono il riferimento “Riccardo”.

Bene, questo non è così!!! I nostri dipendenti rimarranno allocati per sempre nella nostra applicazione, sebbene nessuno li utilizzi più! Questo può essere definito come vero e proprio memory leak, anche se devia leggermente dal significato originale.

La presenza di memory leak dipende da come realizziamo la classe “Dipendente”. Andiamo per gradi: nel seguente esempio NON avviene alcun memory leak:

public class Dipendente {
	public List<Dipendente> Subordinati = new List<Dipendente>();
}

Infatti se l’applicazione perde il riferimento ai dipendenti, il primo che verrà deallocato è il capo “Riccardo” poiché non ha più alcun riferimento. Successivamente verrà deallocata la List poiché non ha più riferimenti e in seguito verranno deallocati tutti e tre i dipendenti referenziati precedentemente dalla lista. Quindi in questo caso non avremo alcun memory leak. Osserviamo invece il seguente caso:

public class Dipendente {
    public Dipendente Superiore;
	public List<Dipendente> Subordinati = new List<Dipendente>();
	public Dipendente(Dipendente superiore) {
	   this.Superiore = superiore;
	}
}

In questo caso vogliamo mantenere per comodità anche un riferimento al superiore di ogni dipendente. Ma analizziamo stavolta cosa succede nel caso in cui l’applicazione non fa più riferimento ai dipendenti. Il capo “Riccardo” dovrebbe essere il primo candidato all’eliminazione, ma non può essere eliminato poiché i tre subordinati mantengono un riferimento. Viceversa, i tre subordinati non possono essere eliminati poiché il capo ne mantiene il riferimento tramite la lista. Questo significa che la struttura non verrà MAI deallocata!! Memory leak!! Una definizione più formale:

Groups of mutually referencing objects which are not directly referenced by other objects and are unreachable can thus become permanently resident; if an application continually generates such unreachable groups of unreachable objects this will have the effect of a memory leak. Weak references may be used to solve the problem of circular references if the reference cycles are avoided by using weak references for some of the references within the group.

In molti articoli come http://www.ibm.com/developerworks/library/j-leaks/index.html o http://blogs.msdn.com/davidklinems/archive/2005/11/16/493580.aspx spesso si risolvono questi problemi eliminando i riferimenti che causerebbero il memory leak adottando soluzioni del tipo:

public class Dipendente : IDisposable {
    public Dipendente Superiore;
	public List<Dipendente> Subordinati = new List<Dipendente>();
	public Dipendente(Dipendente superiore) {
	   this.Superiore = superiore;
	}

	public void Dispose() {
	   foreach(Dipendente subordinato in this.Subordinati) {
	       subordinato.Superiore = null;
	   }
	}
}

public class Application {
    static void main() {
	   using(Dipendente riccardo = new Dipendente(null)) {
	       riccardo.Superiori.Add(new Dipendente(riccardo));
		   riccardo.Superiori.Add(new Dipendente(riccardo));
		   riccardo.Superiori.Add(new Dipendente(riccardo));
	   } // esegue la dispose
	   // perde il riferimento
	}
}

Sinceramente non mi piace l’approccio di “ricordarsi” lo using: troverete ovunque forum del tipo “avete memory leak? La colpa è tua che non fai la dispose degli oggetti Drawing!”. Cosa?? La colpa è mia??? No, le cose non stanno così: chi scrive la libreria non deve caricare agli utilizzatori di dettagli che possono causare problemi!!

La soluzione esiste ed è molto semplice: bisogna pensare i riferimenti a oggetti in termini di POSSESSO (OWNERSHIP). Possiedo, e quindi ho diritto di vita e morte, dell’oggetto a cui mi sto riferendo? Se sì, utilizza un normale riferimento come hai sempre fatto (Strong Reference). Altrimenti usa un WeakReference. Cosa è un WeakReference? Semplicemente è un riferimento debole a un oggetto, che ha validità fin quando esistono Strong Reference che mantengono in vita l’oggetto. Risulta comodo vedere le cose in termini di composizione UML: tutte le composizioni sono Strong Reference, altrimenti sono WeakReference.

Si noti un aspetto importante: queste sono regole generali di buona programmazione che si applicano a prescindere dalla implementazione della GC. Infatti linguaggi come C# o Java la GC elimina riferimenti non più utilizzati dal contesto di esecuzione corrente: eventuali riferimenti circolari isolati saranno quindi eliminati. Questo significa quindi che riferimenti circolari causati nel contesto di esecuzione corrente provocano lo stesso identico problema descritto. Un esempio semplice? La nostra applicazione mantiene un riferimento all’ultimo studente selezionato, lo eliminiamo ma non verrà mai cancellato poiché mantenuto dalla app.

Per evitare quindi memory leak in modo corretto e senza impatti sugli utilizzatori della nostra classe dovremo scrivere:

[
public class Dipendente {
    private WeakReference<Dipendente> _superioreWeak;
    public Dipendente Superiore { get { return _superioreWeak.Target; } }
	public List<Dipendente> Subordinati = new List<Dipendente>();

	public Dipendente(Dipendente superiore) {
	   this._superioreWeak =  new WeakReference<Dipendente>(superiore);
	}
}

public class Application {
    static void main() {
	   Dipendente riccardo = new Dipendente(null);
	   riccardo.Superiori.Add(new Dipendente(riccardo));
	   riccardo.Superiori.Add(new Dipendente(riccardo));
	   riccardo.Superiori.Add(new Dipendente(riccardo));
	} // perde il riferimento
}

I WeakReference risultano quindi molto utili per impedire memory leak causati da riferimenti circolari. Utilizzi tipici sono situazioni composite con riferimento al padre o situazioni di caching, in cui tramite un weak hash map vengono memorizzati gli oggetti senza impedirne la deallocazione (altrimenti nella cache vivrebbero oggetti per sempre!!). Una buona regola è comunque utilizzare un tool per la rilevazione di memory leak, come CLR Profiler.

Posted in .net, design, java, performance | 4 Comments »

Download Snapping / Sticky / Magnetic Windows for WPF

Posted by Ricibald on 19th October 2009

Starting from Sticky Windows on CodeProject (makes your windows snapping like winamp or google talk) I adapted the project developed for standard WinForm in Wpf Application. It works with multiple monitor and with windows vista/7.

DOWNLOAD LINK.

I adapted the following interface to get the app work with WPF App:

    public interface IFormAdapter
    {
        IntPtr Handle { get; }
        Rectangle Bounds { get; set; }
        Size MaximumSize { get; set; }
        Size MinimumSize { get; set; }
        bool Capture { get; set; }
        void Activate();
        Point PointToScreen(Point point);
    }

    public class WinFormAdapter : IFormAdapter
    {
        // Original Code Implementation
    }

    public class WpfFormAdapter : IFormAdapter
    {
        // My Implementation
    }

Enjoy and please give me feedback!

DOWNLOAD LINK.

Posted in .net, download | 12 Comments »

Quando usare String.Intern: i Lock

Posted by Ricibald on 16th April 2009

String è un tipo immutabile che si basa sul pattern Flyweight: ogni volta creiamo una nuova stringa questa prenderà l’istanza memorizzata per quel valore. Un esempio pratico chiarisce tutto:

string s1 = "ciao";    // puntatore: p1
string s2 = "a tutti"; // puntatore: p2
string s3 = s1 + s2;  // puntatore: p3
string s4 = "ciao a tutti"; // puntatore: p3
s1 = s1 + s2; // puntatore: p1
s1 == s3; // true (verosimiglianza dall'override dell'operatore)
(object)s1 == (object)s3;  // false (confronto puntatori)
s1 = String.Inner(s1); // puntatore: p3
(object)s1 == (object)s3;  // true (confronto puntatori)

Questo per dare una spolveratina ai concetti. Il metodo String.Intern consente quindi di restituire il valore del puntatore memorizzato in cache. Ma a cosa può essere utile questa funzione?

Un utilizzo immediato risiede in ragioni di performance: confrontare puntatori è molto più efficiente che confrontare il contenuto. Avere quindi una collezione di stringhe con puntatori intern consente una comparazione molto più efficiente. Normalmente infatti l’approccio in una comparazione dovrebbe essere: per primo confronta i puntatori, altrimenti il contenuto.

Ma esiste un ulteriore utilizzo. Un utilizzo possibile sta nel lock: le funzioni di lock di .NET si basano infatti sul valore del puntatore per effettuare un lock. Immaginiamo quindi un lock di questo tipo:

lock((string)Session["username"]) {
    dbOperation1();
    dbOperation2();
}

Questo lock è sbagliato: infatti se lo stesso utente è collegato da un altro browser il lock potrebbe non essere acquisito. Il seguente metodo consente invece un lock corretto:

lock(String.Intern((string)Session["username"])) {
    dbOperation1();
    dbOperation2();
}

Si noti che questo approccio presuppone l’utilizzo di un unico web server. Se invece abbiamo in cluster differenti server, a seconda del server scelto potremmo avere differenti valori per il puntatore di “username” e l’approccio non sarebbe valido comunque.

Posted in .net | No Comments »

The handshake failed due to an unexpected packet format in Microsoft Dynamics CRM 4.0

Posted by Ricibald on 26th February 2009

Nel CrmService ho provato a connettermi e ricevo il seguente errore:

The handshake failed due to an unexpected packet format

L’eccezione risulta molto generica e vari post sull’argomento non risolvono il problema. Il messaggio indica un’incompatibilità tra cosa viene chiamato e il protocollo atteso. Analizzando il file di configurazione risultava che l’add web reference aveva aggiunto la seguente riga:

    <applicationSettings>
        <MySettings>
            <setting name="MySettings"
                serializeAs="String">
                <value>https://myc-wscrm:80/MSCrmServices/2007/CrmService.asmx</value>
            </setting>
        </MySettings>
    </MySettings>

Come si osserva, era stato specificato automaticamente protocollo https su porta 80 (!!!). Non conosco il motivo di questa impostazione automatica. Comunque basta correggere https in http e tutto funziona

Posted in .net | 1 Comment »

Certificazione MCTS Web verso l’MCPD Enterprise Framework 2.0 – Parte 3/5: 70-528

Posted by Ricibald on 19th February 2009

Questa è la terza parte (vedi la seconda parte) di una serie di pdf che ho scritto per riassumere il contenuto delle certificazioni Microsoft che portano alla certificazione Microsoft MCPD di livello “enterprise” (Distributed).

Logicamente questi pdf li avevo creati per riassumere i concetti che io ritenevo importante riassumere. Potrebbero essere appunti che non vi interessano affatto o che reputate inutili. Viceversa potrebbe essere un’ottima integrazione e un’ottimo punto di partenza per ripassare quanto studiato sul libro ufficiale dell’esame.

TS: Microsoft .NET Framework 2.0 – Web-Based Client Development

Posted in .net | No Comments »