mercoledì 11 febbraio 2015

Terminare Finalmente

Chi proviene dal C++ sa bene che è molto importante rilasciare la memoria allocata precedentemente nello heap. Le classi C++ hanno il distruttore proprio per questo motivo.
Potrebbe sembrare che il metodo finalizer di Java sia l'equivalente del distruttore in C++.

NON LO E' !!!

Il metodo finalizer di Java è da usare soltanto in due casi:

  1. Come rete di protezione per assicurarsi che una risorsa nativa sia stata rilasciata e per questo scopo è stato creato un metodo apposito che l'oggetto client si potrebbe essere dimenticato di chiamare.
  2. Per rilasciare delle risorse native non critiche, cioè risorse la cui occupazione non deve essere rilasciata il prima possibile. Infatti se una classe Java chiama una libreria nativa, il garbage collector non può intervenire sulla parte nativa, quando rilascia l'oggetto in Java, quindi il finalizer in questo caso ha senso, però il programmatore potrebbe comunque fare un metodo di rilascio e chiamarlo.


Il metodo finalizer è chiamato dal Garbage Collector, quindi non c'è la certezza di quando è chiamato: dipende da quale algoritmo di GC è usato e dalla particolare implementazione della virtual machine.
La virtual machine potrebbe anche terminare senza che il finalizer sia mai stato chiamato.
I metodi finalizer rallentano il programma.

Il modo corretto di rilasciare le risorse critiche è un try finally, non il finalizer !

Anche se si chiama System.runFinalization non si ha la garanzia che il finalizer sia chiamato, mentre il System.runFinalizerOnExit e il Runtime.runFinalizerOnExit sono stati deprecati.

Il finalizer pone problemi anche con l'overriding di una sottoclasse, nel caso in cui il programmatore distratto si sia dimenticato di chiamare il super.finalizer() nella sottoclasse, a tal proposito ha senso definire nella superclasse un oggetto come proprietà privata, il quale deve avere il finalizer per liberare le risorse, in modo che, se anche la sottoclasse non chiama il super.finalizer(), quando interviene il garbage collector, questi chiami automaticamente il finalizer dell'oggetto privato, non si sa quando.

Una curiosità per i programmatori C++: la parentesi graffa chiusa } è un operatore nel mondo C++, quindi se abbiamo aperto un file e abbiamo il riferimento nello stack, la graffa chiusa chiama il metodo close() !!!

Questo in Java non succede, perché la parentesi graffa indica soltanto la fine del blocco di codice, si deve ricorrere al try finally o al try-with-resources che accetta oggetti chiudibili e si occupa di chiuderli automaticamente alla fine del blocco try, altra dimostrazione che il finalizer è da evitare come la peste, perché il modo giusto è ricorrere il più possibile al try.

Nessun commento:

Posta un commento