0

问题:如果我使用大 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();
    }
}
4

2 回答 2

1

可能是 ActiveX 组件爆炸,返回 E_OUTOFMEMORY。哪个被翻译成OOM。问题是当您异步运行此代码时,您已经运行了该组件的多个实例。一个 50 MB 的 pdf 文件将需要一堆非托管内存,可能有数百兆字节。

GC.Collect() 调用是偶然的。它释放了您的 fileBytes 数组。它们非常大,并被放入大对象堆中。释放它们需要一个完整的 GC。您的 Collect() 调用会为 ActiveX 组件提供一些喘息的空间,以便从 Windows 堆管理器中窃取非托管内存。

您只是在这里遇到了 32 位进程的基本内存限制。您至少必须限制此组件的实例数量,以避免它们占用过多内存。无论如何,线程很少在 ActiveX 组件上工作,COM 将它们的调用编组到 STA 线程。

于 2010-11-26T19:48:29.727 回答
0

并不真地。一个适时的 GC.Collect 当你知道你需要它是可以接受的做法。虽然我建议你将它移到 LoadFile 函数的末尾(越靠近内存消耗任务的来源越好)。

于 2010-11-26T19:35:20.010 回答