Garbace Collection questo sconosciuto

venerdì 25 marzo 2011 - 16.32
Tag Elenco Tags  C#  |  .NET 3.5  |  Visual Studio 2008

ysdemarc Profilo | Expert

Scusate la domanda demenziale, ho capito a cosa serve la Garbage collection ma non ho affatto compreso come si usa.

im parole povere nel codice cosa scrivo?

E se ho un oggetto di terzi privi di metodo Dispose e quant'altro per poter liberare la memoria come posso usare la garbage collection allo scopo?

ciao
Vincenzo
Programmatore sbilenco

kataklisma Profilo | Senior Member

Ciao!

>Scusate la domanda demenziale, ho capito a cosa serve la Garbage
>collection ma non ho affatto compreso come si usa.
>
>im parole povere nel codice cosa scrivo?

IL GC è un processo del framework .Net non direttamente controllabile dal programmatore, l'algoritmo del GC in piena autonomia cerca gli oggetti non piu referenziati e li elimina dalla memoria.

Buona norma è utilizzare l'interfaccia IDisposable per liberare esplicitamente delle risorse dalla memoria, implementando IDisposable infatti puoi utilizzare il costrutto "using" sui tuoi oggetti, ti faccio un'esempio :

Public class Persona : IDisposable { public void Cammina() { Console.WriteLine("Cammino"); } public void Dispose() { //LIbero tutte le risorse dell'instanza } } public class Test { public static void CreaPersonaEFallaCamminare() { using(Persona IO = new Persona()) { IO.Cammina(); } } }


Ereditando IDisposable ed implementando il tutto in maniera corretta, puoi stare certo che il GC libererà la memoria il piu presto possibile e nel migliore dei modi.

Immagina di avere una classe che utilizza un'oggetto del tipo SqlConnection, nel metodo Dispose della tal classe puoi ad esmepio eseguire una Close() su SqlConnection e la sua Dispose() ad esempio.

Potresti ad esempio liberare le risorse unmanaged e per questo ti riporto ad un link MSDN : http://msdn.microsoft.com/it-it/library/b1yfkh5e.aspx


>E se ho un oggetto di terzi privi di metodo Dispose e quant'altro
>per poter liberare la memoria come posso usare la garbage collection
>allo scopo?

Se la classe è ereditabile puoi ereditarla, implementare Dispose() e gestire le risorse.

>ciao

Ciao!

------------------------------------------
Ignazio Catanzaro

http://blogs.dotnethell.it/swdev/

ysdemarc Profilo | Expert

Grazie sei stato molto esaustivo...

Comunque la classe non è ereditabile e non implementa IDisposable..per cui mi devo rassegnare ad avere Errori di memoria piena..

La mia speranza era che potevo in qualche modo segnalare ad GC la classe e lui ne liberasse la memoria in modo automatico o esplicito.

ciao
Vincenzo
Programmatore sbilenco

kataklisma Profilo | Senior Member

>Grazie sei stato molto esaustivo...

Di nulla :)

>Comunque la classe non è ereditabile e non implementa IDisposable..per
>cui mi devo rassegnare ad avere Errori di memoria piena..
>
>La mia speranza era che potevo in qualche modo segnalare ad GC
>la classe e lui ne liberasse la memoria in modo automatico o
>esplicito.

Esponi meglio il problema, magari sappiamo darti una mano....

------------------------------------------
Ignazio Catanzaro

http://blogs.dotnethell.it/swdev/

ysdemarc Profilo | Expert

Ok, devo elaborare delle immagini fatte da uno scanner abbastanza grosso. Questo scanner produce dei file con 50 documenti e 4 immagini per documento

1 fronte monocromatico
1 retro monocromatico
1 fronte a colori
1 retro a colori

e fa un unico file multitiff (come faccia ad inserire immagini con diversi formati pixel in uno solo per me rimane un mistrero)

l'unico modo per leggere questo file (visto che il normale oggetto bitmap di .net va in errore) è quello di utilizzare un controllo di terze parti ossia al momento ho solo trovato Inlite.ClearImageNet

e vado come segue:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

la classe ImageIO è questa:

using Interop.ClearImage; using System; using System.Drawing; using System.Drawing.Imaging; namespace Inlite.ClearImageNet { public class ImageIO { public ImageIO(); public EComprBitonal compressionBitonal { get; set; } public EComprColor compressionColor { get; set; } public int jpegQuality { get; set; } public double pdfMinImageHeight { get; set; } public double pdfMinImageWidth { get; set; } public EPdfRasterColorMode pdfRasterColorMode { get; set; } public int pdfRasterDpiBitonal { get; set; } public int pdfRasterDpiColor { get; set; } public int pdfRasterDpiGrayscale { get; set; } public EPdfReadMode pdfReadMode { get; set; } public void Append(Bitmap bmp, string fileName); public static void CopyToClipboard(Bitmap bmp); public static Bitmap Create(int width, int height); public static Bitmap Create(int width, int height, PixelFormat fmt); public ImageInfo Info(); public ImageInfo Info(string fileName); public ImageInfo Info(string fileName, int pageNumber); public Bitmap Open(string fileName); public Bitmap Open(string fileName, int pageNumber); public void SaveAs(Bitmap bmp, string fileName); } }
e non possiede nessun metodo er svuotare la memoria.

L'errore di memoria esaurita va circa a 18.000 documenti (qundi 18.000 x 4 immagini)

Suggerimenti?
Vincenzo
Programmatore sbilenco

niccord Profilo | Newbie

Hai provato a mettere il codice dentro il for all'interno di un metodo?
Non sono sicuro cambi qualcosa...però penso di sì

ysdemarc Profilo | Expert

si trova già all'interno di un metodo..

non credo che la scrittura di codice in un metodo o funzione o dove si voglia scriverlo cambi al gestione di memoria, almeno in questo caso.
Vincenzo
Programmatore sbilenco

kataklisma Profilo | Senior Member

>Hai provato a mettere il codice dentro il for all'interno di
>un metodo?
>Non sono sicuro cambi qualcosa...però penso di sì

Non cambia assolutamente nulla.....

Comunque, dovresti riuscire a capire se quel controllo è stato pensato per file in input cosi "grossi".

Il fatto che non implementi IDisposable o comunque che non liberi le risorse managed/unmanaged (se ce ne sono) è abbastanza grave.
La cosa migliore è effettuare dei Test con file di diverse dimensioni , riportare tutto alla Inlite Research e attendere una risposta.

Sembra banale e scontata come cosa, ma è l'unica cosa da fare....questo è un SDK commerciale e non modificabile...che fare quindi? :)

------------------------------------------
Ignazio Catanzaro

http://blogs.dotnethell.it/swdev/

niccord Profilo | Newbie

>non credo che la scrittura di codice in un metodo o funzione
>o dove si voglia scriverlo cambi al gestione di memoria, almeno
>in questo caso.

Da quello che so io cambia invece.
La memoria "temporanea" dovrebbe essere raccolta e liberata dal garbage collector perché le aree di memoria delle variabili stesse non sono più referenziate al termine del metodo.
Per cui se metti tutte le variabili temporanee all'interno di un metodo, il garbage collector dovrebbe riuscire a recuperare le aree di memoria.

kataklisma Profilo | Senior Member

>Da quello che so io cambia invece.
>La memoria "temporanea" dovrebbe essere raccolta e liberata dal
>garbage collector perché le aree di memoria delle variabili stesse
>non sono più referenziate al termine del metodo.
>Per cui se metti tutte le variabili temporanee all'interno di
>un metodo, il garbage collector dovrebbe riuscire a recuperare
>le aree di memoria.

Invece avresti l'esatto contrario : dichiarando un nuovo metodo e inizializzando una variabile di tipo Bitmap all'interno non fai altro che occupare altre aree di memoria, tralasciando il fatto che il GC si aziona ad intervalli di tempo variabili e non ogni qual volta un'oggetto non è più referenziato!

La cosa piu corretta da fare in questo caso è portare fuori dal ciclo la dichiarazione della variabile di tipo Bitmap ed effettuare una GC.Collect() :

ImageIO img = new ImageIO(); int pages = img.Info(fileInput).PageCount; int j = 0; Bitmap pic; for (int i = 0; i < pages; i++) { pic = img.Open(fileInput, i+1); pic.Dispose(); pic = null; GC.Collect(); } img = null;

Il problema principale è che l'utilizzo del metodo Collect della classe statica GC è sconsigliato in quanto al suo richiamo vengono bloccati tutti i thread in esecuzione minando cosi le prestazioni dell'applicazione, se quel for gira per 18.000 volte è un bel problema...fai un po di prove e facci sapere :)

------------------------------------------
Ignazio Catanzaro

http://blogs.dotnethell.it/swdev/

ysdemarc Profilo | Expert

provo così e poi vi facico sapere

grazie mille
Vincenzo
Programmatore sbilenco

lukepet Profilo | Junior Member

Ciao a tutti, mi riaggancio all'argomento perché vorrei dei chiarimenti sull'implementazione dell'interfaccia IDisposable. Vi posto un codice di esempio:

public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); TestObject a = new TestObject(); a.Dispose(); } private void Button_Click(object sender, RoutedEventArgs e) { GC.Collect(); } } public class TestObject : IDisposable { public TestObject() //Costruttore { Console.WriteLine("Costruttore"); } ~TestObject() //Finalize { Dispose(false); Console.WriteLine("Distruttore"); } #region IDisposable protected bool _disposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected void Dispose(bool disposing) { if (!_disposed) { if (disposing) { Console.WriteLine("Dispose"); } _disposed = true; } } #endregion }

Facendo le prove con questo codice ho visto che se io metto a commento la chiamata esplicita al metodo "Dispose" (a.Dispose) nel momento in cui forzo GC.Collect viene invocato il distruttore dell'oggetto TestObject; quindi, se non ho capito male, l'oggetto viene cancellato fisicamente dalla memoria (come è giusto che sia). Mentre se io richiamo il metodo "Dispose" e successivamente forzo il GC.Collect il distruttore della classe non viene più invocato e questo perché, se non ho capito male, l'istruzione "GC.SuppressFinalize(this)" comunica al GC che non è necessario fare il "finalize" dell'oggetto perché è già stato fatto il Dispose...ma facendo in questo modo l'oggetto fisicamente risiede ancora in memoria? Oppure viene comunque cancellato? Se si, in che modo?

Ho inserito il "GC.SuppressFinalize" perché in rete ho visto che molte implementazioni dell'interfaccia IDisposable lo consigliano, è effettivamente un vantaggio? Quale è il modo migliore di implementare IDisposable?

Vi ringrazio in anticipo per ogni chiarimento in merito.

AGGIORNAMENTO:
Come non detto...facendo altri test credo di aver capito come si comporta.

Quando passa nel "finalize" in realtà l'oggetto viene solo "marcato" come cancellabile dal garbage collector che effettivamente lo elimina al successivo ciclo di riciclo.

Il SuppressFinalize invece ottimizza le cose perché comunica al GC che può cancellare fin da subito l'oggetto in quanto è già stato fatto il dispose (e quindi il rilascio di eventuali risorse collegate all'oggetto).

Confermatemi se ho capito bene...thanks
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2017
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5