GC содержит много закрепленных объектов через некоторое время - PullRequest
4 голосов
/ 17 декабря 2008

У меня странное явление, когда я постоянно создаю экземпляр com-обертки, а затем позволяю GC собирать его (не принудительно).

Я тестирую это на .net cf на WinCE x86. Мониторинг производительности с помощью .net Compact Framework удаленного монитора. Собственная память отслеживается с помощью монитора производительности Windows CE Remote из инструментария разработчика платформы.

В течение первых 1000 созданных экземпляров каждый счетчик в perfmon выглядит нормально:

  • куча GC идет вверх и вниз, но среднее значение остается прежним
  • Закрепленные объекты - 0
  • родная память сохраняет то же среднее
  • ...

Однако после этих 1000 (приблизительно) счетчик закрепленных объектов увеличивается и никогда больше не уменьшается. Однако использование памяти остается прежним.

Я не знаю, какой вывод можно извлечь из этой информации ... Это ошибка в счетчиках, это ошибка в моем программном обеспечении?

[EDIT] * * тысячу двадцать-один

Я замечаю, что счетчик закрепленных объектов начинает увеличиваться, как только общее количество байтов используется после стабилизации GC, как и объекты, не перемещаемые счетчиком уплотнения.

Графическое изображение счетчиков http://files.stormenet.be/gc_pinnedobj.jpg

[/ EDIT]

Вот соответствующий код:

    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 голосов
/ 17 декабря 2008

Ну, в вашем коде есть ошибка в том, что вы создаете много экземпляров IDisposable и никогда не вызываете Dispose для них. Я надеюсь, что финализаторы в конечном итоге вступят в игру, но они не должны быть необходимыми. В своем рабочем коде вы распоряжаетесь всем соответствующим образом - и если нет, то есть ли причина, по которой вы не можете?

Если вы добавили запись в финализатор AlphaImage (обнаруживая выгрузку AppDomain и завершение работы приложения, а в этих случаях не регистрируя!), Он показывает, что вызывается финализатор?

РЕДАКТИРОВАТЬ: Одна потенциальная проблема, которая, вероятно, не кусает вас, но может стоить исправить в любом случае - если по какой-либо причине вызов CreateImageFromBuffer не удался, у вас все еще есть память, созданная AllocHGlobal, и это в настоящее время будет утечка. Я подозреваю, что это не проблема, иначе это будет более эффектно, но стоит подумать.

3 голосов
/ 17 декабря 2008

Я сомневаюсь, что это ошибка в RPM. То, что у нас здесь нет, это какое-то понимание материала Ppb.Drawing. Место, где я вижу потенциальную проблему, - это вызов GetIImagingFactory. Что оно делает? Вероятно, это всего лишь одноразовый сборщик, но за этим я бы охотился.

Я также вижу AllochHGlobal, но нигде не вижу, чтобы выделение освободилось. Сейчас я бы сосредоточился на этом.

...