问题:如果我使用大型PDF文件(50Mb,1500页)异步调用LoadFile()几次(10-20次就足够了),那么我会很快得到OutOfMemory异常。如果我在EndInvoke()之后调用GC.Collect(),那么它可以解决问题。
同步调用很有效(不会发生内存泄漏)。
关于如何在不直接调用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 :(得分:1)
可能是ActiveX组件轰炸,返回E_OUTOFMEMORY。哪个被翻译成OOM。问题是,当您异步运行此代码时,您已经运行了该组件的多个实例。一个50 MB的pdf文件将需要一堆非托管内存,可能需要数百兆字节。
GC.Collect()调用是偶然的。它释放了你的fileBytes数组。它们非常大并且被放入大物体堆中。它需要一个完整的GC来释放它们。您的Collect()调用所做的,为ActiveX组件提供了一些喘息空间,可以从Windows堆管理器中窃取非托管内存。
您只是在这里遇到了32位进程的基本内存限制。您必须至少限制此组件的实例数,以避免让它们吞噬太多内存。无论如何,线程很少适用于ActiveX组件,COM会调用它们对STA线程的调用。
答案 1 :(得分:0)
不是真的。一个很好的定时GC.Collect当你知道你需要它是可以接受的做法。虽然我建议你把它移到LoadFile函数的末尾(越接近消耗任务的内存源越多)。