2012-02-07 4 views
5

Ho un requisito insolito per il codice su cui sto lavorando. Sto usando una libreria di terze parti inaffidabile per fare una scansione di codici a barre (smette di funzionare dopo aver eseguito troppe volte). Per ovviare a questo problema, ho deciso di eseguire il lavoro in un AppDomain separato e quindi di scaricare AppDomain al termine. Questa è una foto semplicistico, ma precisa, di quello che sto facendo:Perdita di memoria brutto durante il caricamento del codice in AppDomain

string domainID = Guid.NewGuid().ToString(); 
AppDomainSetup setup = new AppDomainSetup(); 
AppDomain domain = AppDomain.CreateDomain(domainID, null, setup); 

string result = null; 
try 
{ 
    domain.SetData("stream", stream); 
    domain.DoCallBack(ScanningContext.DoWork); 

    result = domain.GetData("result") as string; 
} 
finally 
{ 
    AppDomain.Unload(domain); 
} 

return result; 

public static void DoWork() 
{ 
    Stream s = AppDomain.CurrentDomain.GetData("stream") as Stream; 
    ObjectHandle handle = AppDomain.CurrentDomain.CreateInstance("Scanning", 
     "Scanner"); 

    Scanning.Scanner scanner = (Scanning.Scanner)handle.Unwrap(); 
    Scanning.Result[] results = scanner.Scan(s); 

    AppDomain.CurrentDomain.SetData("result", results[0].Text); 
} 

"Scanner" è una classe wrapper intorno alla biblioteca che sto utilizzando. Si trova nell'assembly "Scanning"; un progetto separato solo per questo scopo.

ScanningContext.DoWork è un metodo statico che si trova nell'assembly del mio servizio.

Il mio problema con questo metodo è che c'è una perdita di memoria in qualche luogo. La memoria continua a crescere (quando viene chiamato questo codice, ovviamente) fino a quando non vengono lanciate OutOfMemoryExceptions.

Non riesco a trovare la perdita da nessuna parte. Tutti i miei flussi sono disposti. Tutti i miei array di byte vengono annullati. Sto cancellando le liste, tutto ciò che ha funzionato per me in passato. Sono sicuro al 90% circa che la perdita sia correlata a questa roba AppDomain. Questa è la mia prima volta che la uso, quindi probabilmente sto facendo qualcosa di sbagliato.

Sono aperto a un altro approccio oltre a AppDomains. Richiedo la possibilità di restituire risultati dalla classe "Scanner", quindi generare un processo non è un'opzione.

+0

Si dice che è possibile eseguire il codice di terze parti almeno un paio di volte. Quindi, puoi escludere l'ultima incertezza del 10% verificando se la perdita esiste anche senza utilizzare domini app? –

+2

Rimuovere il codice di chiamata dello scanner, restituire un risultato fisso e controllare se la memoria perde ancora lì, quindi il suo problema di AppDomain, altrimenti è il problema della libreria di terze parti. –

+0

Il vecchio metodo consuma molta memoria, circa 250.000k mentre guardo ora, quindi, l'uso della memoria non è buono. Tuttavia non ha esaurito la memoria come sta facendo il mio nuovo approccio. Quindi per rispondere alla tua domanda, no non posso escludere l'altro 10%, ho dovuto riscrivere un po 'di codice per usare AppDomains in modo da poter introdurre la perdita in quel momento. – Matthew

risposta

2

Il metodo AppDomain.Unload avvia un thread separato per scaricare il dominio, che potrebbe non riuscire per vari motivi (i thread che eseguono codice non gestito è un problema). Ecco un esempio di codice che controlla se il dominio dell'app è stato scaricato (preso da msdn docs):

try 
{ 
Console.WriteLine(); 
// Note that the following statement creates an exception because the domain no longer exists. 
Console.WriteLine("child domain: " + domain.FriendlyName); 
} 
catch (AppDomainUnloadedException e) 
{ 
Console.WriteLine("The appdomain MyDomain does not exist."); 
}