一段时间后,GC包含大量固定对象

4

我在连续实例化一个com-wrapper并让GC对其进行收集(非强制性)时遇到了奇怪的现象。

我正在WinCE x86上测试.net cf。使用.net Compact framework远程监视器监控性能。使用平台生成工具包中的Windows CE Remote性能监视器跟踪本机内存。

在前1000个创建的实例期间,每个perfmon计数器都正常:

  • GC堆上下波动,但平均值保持不变
  • 固定对象为0
  • 本机内存保持相同的平均值
  • ...

然而,在这1000个实例之后(大约),固定的对象计数器上升,并且数量再也不会下降。然而,内存使用量保持不变。

我不知道如何从这些信息中得出结论...这是计数器中的错误吗?还是我的软件有问题?

[编辑]

我注意到,当GC稳定后,总字节数达到一定值时,固定对象计数器开始上升,未被压缩器移动的对象计数器也是如此。

计数器的图形 http://files.stormenet.be/gc_pinnedobj.jpg

[/编辑]

下面是相关代码:

    private void pButton6_Click(object sender, EventArgs e) {
        if (_running) {
            _running = false;
            return;
        }
        _loopcount = 0;
        _running = true;

        Thread d = new Thread(new ThreadStart(LoopRun));
        d.Start();
    }

    private void LoopRun() {
        while (_running) {
            CreateInstances();
            _loopcount++;
            RefreshLabel();
        }
    }

    void CreateInstances() {
        List<Ppb.Drawing.Image> list = new List<Ppb.Drawing.Image>();
        for (int i = 0; i < 10; i++) {
            Ppb.Drawing.Image g = resourcesObj.someBitmap;
            list.Add(g);
        }

    }

Image对象包含一个AlphaImage:

    public sealed class AlphaImage : IDisposable {
    IImage _image;
    Size _size;
    IntPtr _bufferPtr;

    public static AlphaImage CreateFromBuffer(byte[] buffer, long size) {
        AlphaImage instance = new AlphaImage();
        IImage img;
        instance._bufferPtr = Marshal.AllocHGlobal((int)size);
        Marshal.Copy(buffer, 0, instance._bufferPtr, (int)size);
        GetIImagingFactory().CreateImageFromBuffer(instance._bufferPtr, (uint)size, BufferDisposalFlag.BufferDisposalFlagGlobalFree, out img);
        instance.SetImage(img);
        return instance;
    }

    void SetImage(IImage image) {
        _image = image;
        ImageInfo imgInfo;
        _image.GetImageInfo(out imgInfo);
        _size = new Size((int)imgInfo.Width, (int)imgInfo.Height);
    }

    ~AlphaImage() {
        Dispose();
    }

    #region IDisposable Members

    public void Dispose() {
        Marshal.FinalReleaseComObject(_image);
    }
}
2个回答

4

嗯,在您的代码中存在一个错误,即您创建了许多IDisposable实例,但从未调用Dispose。我希望最终器最终会启动,但它们实际上不应该是必需的。在您的生产代码中,您是否适当地处理了所有内容 - 如果没有,是否有某些原因使您无法这样做?

如果在AlphaImage终结器中放置一些日志记录(检测AppDomain卸载和应用程序关闭,并在这些情况下不进行日志记录!)是否显示调用终结器?

编辑:可能存在一个问题,这个问题可能并没有影响到您,但仍然值得修复 - 如果CreateImageFromBuffer的调用由于任何原因失败,则仍然拥有AllocHGlobal创建的内存,并且当前将泄漏该内存。我认为这不是问题,否则它将更加引人注目,但值得思考。


最终器正在被调用(如果不这样做,我将在几秒钟内耗尽内存)。实际上,有一个Image类包装器围绕AlphaImage类,它调用AlphaImage的Dispose方法。 - Stormenet
不过,你不应该依赖终结器 - 这就是 IDisposable 的作用。 你应该使用 using (image) { ... } 结构来确保尽快调用 Dispose 方法。此外,在 Dispose() 中使用 GC.SuppressFinalize(),以便对已释放对象不会调用终结器。 - configurator
@configurator:关于suppressFinalize,我已经添加了。但是,由于它是一张图片,就像普通的位图一样,它被用在用户控件中,所以你不能使用using结构,所以我必须依赖于终结器。 - Stormenet
用户控件应该有一个从顶部控件到底部的Dispose树。这就是设计者.cs自动生成的dispose方法的作用之一。 这应该调用您的用户控件,它应该处理包含资源的任何子级。 - Quibblesome

3

我怀疑这不是RPM的漏洞。我们在这里缺乏有关Ppb.Drawing的任何了解。我认为潜在问题可能出现在GetIImagingFactory调用中。它是做什么的?它可能只是一个单例获取器,但这是我要追踪的东西。

我还看到了一个AllochHGlobal,但我没有看到该分���是否被释放。暂时我会把焦点放在这里。


GetIImagingFactory确实是一个单例获取器。AllocHGlobal分配的内存由com对象本身释放。在CreateImageFromBuffer调用中,我指定它应该释放HGlobal内存中的内存。 - Stormenet
是分配导致了固定的对象。COM对象释放了内存,但.NET CLR仍然认为它正在使用中,从而导致泄漏。 - Stormenet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接