Есть ли разница в размещении Icon и Bitmap?

Я отлаживал утечки ресурсов в своем приложении и создал тестовое приложение для проверки утечек объектов GDI. В OnPaint я создаю новые иконки и новые растровые изображения, не удаляя их. После этого я проверяю увеличение объектов GDi в диспетчере задач для каждого из случаев. Однако, если я продолжаю перекрашивать главное окно своего приложения, количество объектов GDI для значков увеличивается, но для растровых изображений изменений нет. Есть ли какая-то конкретная причина, по которой значки не очищаются так же, как растровые изображения?

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        // 1. icon increases number of GDI objects used by this app during repaint.
        //var icon = Resources.TestIcon;
        //e.Graphics.DrawIcon(icon, 0, 0);

        // 2. bitmap doesn't seem to have any impact (only 1 GDI object)
        //var image = Resources.TestImage;
        //e.Graphics.DrawImage(image, 0, 0);
    }
}

Результат испытаний:

  1. Без значков и растровых изображений — 30 объектов GDI
  2. С растровыми изображениями — 31 объект GDI число не меняется.
  3. С иконками - 31 и то число увеличивается если перекрашивать окно.

person username    schedule 13.02.2015    source источник
comment
Возможное объяснение состоит в том, что это эффект сборки мусора: Bitmap обычно большой, а Icon маленький настолько большой, что Bitmap запускает сборку мусора, которая очищает Bitmapудаляет их), но не Icons   -  person Dmitry Bychenko    schedule 13.02.2015
comment
@DmitryBychenko Разве недавно созданные небольшие объекты не должны принадлежать к поколению 0 и очищаться чаще?   -  person username    schedule 13.02.2015
comment
да, поколение 0 склонно к сбору; другая проблема заключается в том, что сборщик мусора обращает внимание на размер кеша ЦП и т. д., поэтому большой объект может вызвать сборку мусора.   -  person Dmitry Bychenko    schedule 13.02.2015
comment
@DmitryBychenko Думаю, нет простого способа проверить это экспериментально. Кстати, я использую маленькие изображения, они не должны сильно отличаться по размеру.   -  person username    schedule 13.02.2015
comment
Эти цифры слишком малы. Вы бы протекали, если бы числа продолжали расти и расти, никогда не уменьшаясь при каждом вызове краски.   -  person LarsTech    schedule 13.02.2015
comment
Поскольку вы, по-видимому, используете статический ресурс, пытались ли вы сохранить растровую копию и использовать вместо нее DrawImage? icon.ToBitmap(). Таким образом, вам нужно будет только один раз обратиться к значку в вашем коде.   -  person Raheel Khan    schedule 16.03.2015
comment
Взгляните на исходный код .net framework. Поиск по DrawIcon. - referencesource.microsoft.com/#System.Drawing /commonui/Система/   -  person João Luiz Grigoletti    schedule 24.03.2015
comment
Что можно понять из краткого взгляда, который я дал коду, так это то, что когда экземпляр Graphic имеет background , значок преобразуется в растровое изображение перед рендерингом, чтобы избежать проблем с альфа-каналом и сохранить ваш рендеринг в GDI +, избегая использования GDI. Теперь не знаю, включает ли этот фонд фоновую форму   -  person João Luiz Grigoletti    schedule 24.03.2015


Ответы (1)


Я считаю, что вам нужно позаботиться об иконках вручную. Я немного поискал и обнаружил, что GC заботится о растровых изображениях, но не об иконках. Формы иногда сохраняют свою собственную копию значков (я не знаю, почему). Способ удаления значков можно найти здесь: http://dotnetfacts.blogspot.com/2008/03/things-you-must-dispose.html

[DllImport("user32.dll", CharSet = CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);

private void GetHicon_Example(PaintEventArgs e)
{
// Create a Bitmap object from an image file.
Bitmap myBitmap = new Bitmap(@"c:\FakePhoto.jpg");

// Draw myBitmap to the screen.
e.Graphics.DrawImage(myBitmap, 0, 0);

// Get an Hicon for myBitmap.
IntPtr Hicon = myBitmap.GetHicon();

// Create a new icon from the handle.
Icon newIcon = Icon.FromHandle(Hicon);

// Set the form Icon attribute to the new icon.
this.Icon = newIcon;

// Destroy the Icon, since the form creates
// its own copy of the icon.
DestroyIcon(newIcon.Handle);
}
person gregyjames    schedule 02.04.2015