Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Утечка пямяти


Автор: lightforever 1.1.2011, 16:45
Имеется очень простенький код:

 
Код

    static Bitmap get_new_bitmap()
        {
            return new Bitmap(1000, 1000);
        }
        static void Main(string[] args)
        {
         
            Bitmap bitmap = new Bitmap(1, 1);

            for (int i = 0; i < 10000; i++)
            {
                bitmap = get_new_bitmap();
            }
        }


Но при запуске получается сильная утечка памяти в get_new_bitmap() , т.к. он возвращать то возвращает мне Новый объект, однако почему-то сборщик мусора не хочет удалять старый Объект из памяти, который вернул мне в предыдущем вызове
get_new_bitmap(). Можно узнать почему? Как сделать, чтобы  удалялся старый объект?

Добавлено через 9 минут и 19 секунд
Как решить эту проблему я понял, достаточно принудительно заставить сборщик мусора произвести чистку:

Код

      System.GC.Collect();
       System.GC.WaitForPendingFinalizers();


Но остаётся вопрос: я всегда думал, что сборщик мусора обязан сам производить чистку в этой ситуации. Почему он этого не делает?
   


Автор: CYBERDREAM 1.1.2011, 19:26
У меня все без проблем. 
Попробуй 
Код

for (int i = 0; i < 10000; i++)
            {
                bitmap.Dispose();
                bitmap = get_new_bitmap();
            }

Автор: KelTron 2.1.2011, 20:07
Цитата(lightforever @  1.1.2011,  16:45 Найти цитируемый пост)
Но остаётся вопрос: я всегда думал, что сборщик мусора обязан сам производить чистку в этой ситуации. Почему он этого не делает?

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

Цитата(lightforever @  1.1.2011,  16:45 Найти цитируемый пост)
Как решить эту проблему я понял, достаточно принудительно заставить сборщик мусора произвести чистку:

Это не решение "проблемы", т.к. проблемы нет. Это, наоборот, потенциальное добавление проблем. Вызывать GC ручками нужно только в крайних случаях, например, при работе с COM объектами.

Есть очень хорошее правило, при работе с управляемой памятью: "выделил и забыл".

Автор: Любитель 3.1.2011, 01:06
Читаем про IDisposable и оператор using.

Автор: МастерФломастер 11.4.2011, 14:20
Тоже столкнулся с утечкой памяти, имею в чужом, большом проекте такую конструкцию:

Код

void Save()
{
obj = null;
obj = new ObjClass();
}


Проблема в том, что старый obj остается в памяти, несмотря на обнуление ссылки на него. Вообще проблема была обнаружена т.к. obj не "отписывался" от событий, на которые подписан и продолжал делать свою работу вместе с новым экземпляром. Я то конечно отписал его от событий, пользователь косяков больше не видит, но после небольшого теста - запуска цикла всего лишь с 10 save'ми - свободной памяти стало на 230мб меньше smile   Погуглив, решил что лучшее решение - реализовать метод Dispose(). Но! Надо сказать obj - очень сложный, большой объект, который включает в себя много других больших, сложных объектов, которые... и так далее. Таких классов порядка 500. Значит, для каждого надо реализовать Dispose(). Что делать мягко говоря не хочется, по крайней мере пока, т.к. только начинаю разбираться с проектом.

есть ли способ удалить obj попроще, не переписывая весь проект?

для спокойствия моей совести было бы достаточно, если бы сборщик мусора когда-нибудь очистил память, только сдается мне никогда этого не случится
простенький пример, как мне кажется аналогичный моему случаю :
Код

public partial class Form1 : Form
{
    private Form f;

    public Form1()
    {
        InitializeComponent();
        button1.Click += new EventHandler(button1_Click);
    }

    void button1_Click(object sender, EventArgs e)
    {
        if (f != null)
        {
            //f.Dispose(); //1й вариант работает замечательно, старая форма удаляетя

            f = null;      //2й вариант - форма остается
            GC.Collect();  //и даже принудительная сборка мусора не помогает
        }
        f = new Form1();
        f.Show();
    }
}


При втором варианте - формы плодятся, старые не исчезают, я наивно полагал что все ссылки на форму удалил и она удалится сборщиком мусора. Почему не удаляется? И что надо сделать чтобы сборщик мусора ее удалил сам (без помощи Dispose).

Ещё один вопрос родился: можно ли получить все ссылки на заданный объект? Может в процессе отладки можно?

Автор: bend0r 11.4.2011, 14:49
Если ссылки обнулены то никакой утечки не будет. для потенциально больших обьектов типа Bitmap сделан Dispose

Автор: МастерФломастер 11.4.2011, 16:31
хм.. ну у меня утечка есть - факт. Вероятно, потому что, не все ссылки обнуляются, например большинство дочерних объектов ссылаются на родителя. Как найти и обнулить ВСЕ ссылки для меня вопрос открытый.

И прокомментируйте, пожалуйста, пример с формами, там вот тоже ссылка вроде как обнуляется, а толку нет.

Автор: neutrino 11.4.2011, 16:51
Kомпилятор оптимизирует твой код и просто выкидывает f=null;
Попробуй написать f.Dispose. Или как-нибудь использовать f:

f=null;
if (f!=null) Console.Write("Something fucked up definitely!");

Автор: МастерФломастер 11.4.2011, 17:32
уфффф


f=null;
if (f!=null)  - не выполнится никогда!

ссылка обнуляется, ниче компилятор не выкидывает!  Вы запустите пример у себя. Сначала первый вариант, затем второй. Почуствуйте разницу! с каждым кликом появляется новая форма, a старые остаются.

в случае с формой Dispose - превосходный выход, но у меня в проекте ни один класс не имеет такого метода.  Поэтому я пытаюсь найти способ удалить таки этот объект.


Автор: Экскалупатор 11.4.2011, 22:58
Цитата(МастерФломастер @  11.4.2011,  16:32 Найти цитируемый пост)
в случае с формой Dispose - превосходный выход, но у меня в проекте ни один класс не имеет такого метода.

ну так реализуй его, он определен в интерфейсе IDisposeble, наследуй и пиши.

кстати, где то читал что с делегатами у GC косяк. т.е. если класс ClassA, подписывается на событие в другом классе ClassB(ессно используя для этого делегаты), то даже если экземпляр ClassB уже не существует, то все равно экземпляр ClassA остается, потому что ожидает события и GC не считает необходимым его удалять. как то так вроде...

Автор: gambit 12.4.2011, 12:57
Цитата(lightforever @  1.1.2011,  16:45 Найти цитируемый пост)
Как решить эту проблему я понял, достаточно принудительно заставить сборщик мусора произвести чистку:

самой кривейший вариант. Если бы у меня на проекте кто ниб вызовет GC сам - тут же уволю нахрен. (Естественно ситуации возможны разные, но надо настолько обосновать, что проще плюнуть и не писать))) Я за свою жисть ни разу не встречал необходимости ручного сбора мусора, а вот заметок типа "не трогайте этот рычаг" очень много где видел, в том числе и в так излюбленном всеми Рихтере.

Автор: bend0r 12.4.2011, 14:57
Цитата(МастерФломастер @ 11.4.2011,  16:31)
хм.. ну у меня утечка есть - факт. Вероятно, потому что, не все ссылки обнуляются, например большинство дочерних объектов ссылаются на родителя. Как найти и обнулить ВСЕ ссылки для меня вопрос открытый.

И прокомментируйте, пожалуйста, пример с формами, там вот тоже ссылка вроде как обнуляется, а толку нет.

утечки памяти в моем понимание тут нету. то что сборщик не выполняется сразу после обнуления ссылок это логично, процедура эта относительно ресурсоемкая ...
если приложения постоянно создает большое количество больших обьектов, при этом каждый раз в новых адресах памяти, то тут проблема либо в архитектуре либо в реализации самого приложения

Автор: gambit 12.4.2011, 15:48
Цитата(bend0r @  12.4.2011,  14:57 Найти цитируемый пост)
утечки памяти в моем понимание тут нету. то что сборщик не выполняется сразу после обнуления ссылок это логично

кстати мой эмоциональный предыдущий высер затмил этот главный факт - почитайте в каких случаях и как вызывается сборщик мусора, про поколения и общие принципы работы, и тогда вы поймете почему он не отрабатывает сразу.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)