开发者

Invoking method asynchronously several times results in OutOfMemory exception

开发者 https://www.devze.com 2023-01-27 16:26 出处:网络
Problem: if I invoke LoadFile() several times (10-20 times is enough) asynchronously using the big PDF file (50Mb, 1500 pages) then I get OutOfMemory exception rather quickly. If I call GC.Collect() a

Problem: if I invoke LoadFile() several times (10-20 times is enough) asynchronously using the big PDF file (50Mb, 1500 pages) then I get OutOfMemory exception rather quickly. If I call GC.Collect() after EndInvoke() then it resolves the problem.

Synchronous invocation works great (no memory leaks occur).

Any ideas on how to resolve it without calling GC.Collect() directly?

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.Open开发者_Python百科Buffer(fileBytes, fileBytes.Length, "");
        this.pdfOcxViewer.CloseFile();
    }
}


It is probably the ActiveX component that bombs, returning E_OUTOFMEMORY. Which gets translated to OOM. The problem is that you've got multiple instances of that component running when you runs this code asynchronously. A 50 MB pdf file is going to require a bunch of unmanaged memory, several hundreds of megabytes probably.

The GC.Collect() call works by accident. It frees your fileBytes arrays. They are quite large and get put in the Large Object Heap. It takes a full GC to get them released. Which your Collect() call does, giving the ActiveX component some breathing room to steal unmanaged memory from the Windows heap manager.

You are just hitting the fundamental memory limitations of a 32-bit process here. You'll have to at least limit the number of instances of this component to avoid having them gobble too much memory. Threading rarely works on ActiveX components anyway, COM marshals their calls to an STA thread.


Not really. A well timed GC.Collect when you know you need it is acceptable practice. Although I recommend you move it to the end of LoadFile function (the closer to the source of memory consuming task the better).

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号