0

問題:如果我使用大的PDF文件(50Mb,1500頁)異步調用LoadFile()多次(10-20次就足夠了),那麼我會很快得到OutOfMemory異常。如果我在EndInvoke()之後調用GC.Collect(),那麼它可以解決問題。多次異步調用方法會導致OutOfMemory異常

同步調用效果很好(不會發生內存泄漏)。

關於如何解決它,而不直接調用GC.Collect()的任何想法?

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Open_Click(object sender, EventArgs e) 
    { 
     MethodInvoker invoker = this.LoadFile; 
     AsyncCallback callback = CallBack; 

     invoker.BeginInvoke(callback, null); 

     // Synchronous call. 
     // LoadFile(); 
    } 

    private void CallBack(IAsyncResult ar) 
    { 
     AsyncResult result = (AsyncResult)ar; 

     MethodInvoker invoker = (MethodInvoker)result.AsyncDelegate; 
     invoker.EndInvoke(ar); 

     // GC.Collect(); 
    } 

    private void LoadFile() 
    { 
     byte[] fileBytes = File.ReadAllBytes(@"c:\50mb.pdf"); 

     // Third party OCX component for viewing PDF files. 
     this.pdfOcxViewer.OpenBuffer(fileBytes, fileBytes.Length, ""); 
     this.pdfOcxViewer.CloseFile(); 
    } 
} 

回答

0

不是。當你知道你需要的時候,一個準時的GC.Collect是可以接受的做法。雖然我建議您將它移動到LoadFile函數的末尾(越接近內存消耗任務的來源越好)。

1

它可能是炸彈的ActiveX組件,返回E_OUTOFMEMORY。它被翻譯成OOM。問題在於,當您異步運行此代碼時,您已經運行了該組件的多個實例。一個50 MB的pdf文件將需要一堆非託管內存,可能數百兆字節。

GC.Collect()調用是偶然的。它釋放你的fileBytes數組。它們非常大,並被放入大對象堆中。它需要一個完整的GC來讓他們發佈。您的Collect()調用會執行哪些操作,從而爲ActiveX組件提供一些喘息空間,以便從Windows堆管理器中竊取非託管內存。

你只是在這裏觸及32位進程的基本內存限制。你必須至少限制這個組件的實例數量,以避免讓它們吞噬太多的內存。線程很少適用於ActiveX組件,COM將它們的調用編組到STA線程。

+0

爲什麼你認爲組件的多個實例正在運行?包裝組件的控件顯然已經有了一個實例。 – Corvin 2010-11-29 12:42:56