2012-02-07 49 views
5

我對我正在處理的某些代碼有不尋常的要求。我使用不可靠的第三方庫進行條碼掃描(運行太多次後停止工作)。爲了解決這個問題,我決定在單獨的AppDomain中完成這項工作,然後在完成時卸載AppDomain。這是我做的一個簡單,但準確,圖片:在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); 
} 

「掃描儀」是圖書館週圍的包裝類我使用。它位於「掃描」程序集中;一個單獨的項目就是爲了這個目的。

ScanningContext.DoWork是一個靜態方法,位於我的服務的程序集中。

這個方法的問題是有一個內存泄漏的地方。內存不斷增長和增長(當然這個代碼被調用了)直到OutOfMemoryExceptions被拋出。

我找不到泄漏的地方。我的所有流都正在處理中。我所有的字節數組都被清零。我正在清單,過去一切爲我工作的東西。我大概有90%的人相信漏洞與這個AppDomain的東西有關。這是我第一次使用它,所以我可能做錯了什麼。

我打開除AppDomains之外的另一種方法。我確實需要從「掃描儀」類返回結果的能力,因此產生過程不是一種選擇。

+0

你說你至少可以運行第三方代碼幾次。那麼你可以通過檢查是否存在漏洞,使用應用程序域來排除最後10%的不確定性嗎? – 2012-02-07 14:13:40

+2

刪除掃描器調用代碼,返回一個固定的結果,並檢查內存是否仍然存在泄漏,然後是其appDomain問題,否則其第三方庫問題。 – 2012-02-07 14:21:09

+0

舊方法消耗大量內存,大約25萬k它現在,所以它的內存使用並不好。然而,它並沒有像我的新方法所做的那樣耗盡內存。因此,要回答你的問題,不,我不能排除其他10%,我不得不重寫一些代碼來使用AppDomain,以便當時可以引入泄漏。 – Matthew 2012-02-07 14:21:20

回答

2

AppDomain.Unload方法啓動一個單獨的線程來卸載域,由於各種原因(執行非託管代碼的線程是一個問題)該域可能會失敗。下面是一個示例代碼,用於檢查應用程序域是否已卸載(取自msdn文檔):

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."); 
}