WPF. Финализаторы не вызываются. Утечка памяти
От: igor-booch Россия  
Дата: 14.06.20 15:04
Оценка:
В продолжении темы http://rsdn.org/forum/dotnet/7753095.1
Автор: igor-booch
Дата: 13.06.20

Создал минимальное воспроизводящее приложение.

Условия воспроизведения:
1) Visual Studio 2017
2) Приложение WPF
3) Запуск приложение под отладчиком
4) код окна WPF

using System.Windows;

namespace ReproduceFinalizerMemoryLeak
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            do
            {
                Item item = new Item();
            } while (true);

            InitializeComponent();
        }
    }

    public class Item
    {
        private byte[] _bytes;

        public Item()
        {
            _bytes = new byte[10000];
        }

        ~Item()
        {

        }
    }
}


Что присходит:
Этот код отваливается с OutOfMemoryException. Финализаторы Item() не вызываются.

В моем реальном WPF приложении утечка памяти просходит без отладки и в более мягких условиях, но проявления те же: финализаторы не вызываются, происходит учечка памяти.
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Re: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 14.06.20 16:21
Оценка:
во-первых, при отладке код работает по-другому, если ты добавишь в деконструктор вот такой код:
 ~Item()
        {
            using (System.IO.StreamWriter file =    new System.IO.StreamWriter(System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), @"WriteLines.txt"), true))
            {
                file.WriteLine("Item's finalizer is called.");
            }
            Console.WriteLine("Item's finalizer is called.");
        }


скомпилируешь под релиз и запустишь, то ты увидишь, что ничего не отваливается, а деконструктор вызывается

во-вторых, проблема у тебя совсем другая, в wpf источники утечки, как правило , совсем другие, так что данный пример- не в тему

сорри, надо и
do
            {
                Item item = new Item();
                GC.Collect();
                GC.WaitForPendingFinalizers();
            } while (true);


вызывать
Отредактировано 14.06.2020 16:57 takTak . Предыдущая версия .
Re: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 14.06.20 18:30
Оценка:
хм.. занятный пример: если вместо

 _bytes = new byte[10000]


сделать

 _bytes = new byte[100000]


то тогда всё работает

либо надо вызывать

do
            {
                Item item = new Item();
                GC.Collect();
                GC.WaitForPendingFinalizers();
               
            } while (true);
Re[2]: WPF. Финализаторы не вызываются. Утечка памяти
От: Osaka  
Дата: 14.06.20 20:07
Оценка:
T>сорри, надо и
T>
T>do
T>            {
T>                Item item = new Item();
T>                GC.Collect();
T>                GC.WaitForPendingFinalizers();
T>            } while (true);
T>


T>вызывать

Вроде достаточно sleep(0) внутри цикла вызывать.
Re[3]: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 14.06.20 20:18
Оценка:
T>>сорри, надо и
T>>
T>>do
T>>            {
T>>                Item item = new Item();
T>>                GC.Collect();
T>>                GC.WaitForPendingFinalizers();
T>>            } while (true);
T>>


T>>вызывать

O>Вроде достаточно sleep(0) внутри цикла вызывать.

не-а, сам по себе Thread.Sleep(1), конечно, context switch производит, но от memory leak это не избавляет
Re: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 14.06.20 20:46
Оценка:
IB>Что присходит:
IB>Этот код отваливается с OutOfMemoryException. Финализаторы Item() не вызываются.

IB>В моем реальном WPF приложении утечка памяти просходит без отладки и в более мягких условиях, но проявления те же: финализаторы не вызываются, происходит учечка памяти.


забавно: если деконструктор

~Item()
{
}


полностью убрать, то всё работает
Re: WPF. Финализаторы не вызываются. Утечка памяти
От: VladCore  
Дата: 14.06.20 20:57
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>В продолжении темы http://rsdn.org/forum/dotnet/7753095.1
Автор: igor-booch
Дата: 13.06.20

IB>Создал минимальное воспроизводящее приложение.



а так?

IB>
IB>using System.Windows;

IB>namespace ReproduceFinalizerMemoryLeak
IB>{
IB>    /// <summary>
IB>    /// Interaction logic for MainWindow.xaml
IB>    /// </summary>
IB>    public partial class MainWindow : Window
IB>    {
IB>        public MainWindow()
IB>        {
IB>            do
IB>            {
IB>                TheMethod();
IB>            } while (true);

IB>            InitializeComponent();
IB>        }
        
        TheMethod() { Item item = new Item(); }
IB>    }

IB>    public class Item
IB>    {
IB>        private byte[] _bytes;

IB>        public Item()
IB>        {
IB>            _bytes = new byte[10000];
IB>        }

IB>        ~Item()
IB>        {

IB>        }
IB>    }
IB>}
IB>


IB>Что присходит:

IB>Этот код отваливается с OutOfMemoryException. Финализаторы Item() не вызываются.

IB>В моем реальном WPF приложении утечка памяти просходит без отладки и в более мягких условиях, но проявления те же: финализаторы не вызываются, происходит учечка памяти.
Re[2]: WPF. Финализаторы не вызываются. Утечка памяти
От: Ночной Смотрящий Россия  
Дата: 14.06.20 21:05
Оценка:
Здравствуйте, takTak, Вы писали:

T>забавно: если деконструктор

T>полностью убрать, то всё работает

Чего ж тут забавного? Объекты перестает держать fqueue и GC прекрасно справляется со сборкой.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[3]: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 14.06.20 21:12
Оценка:
T>>забавно: если деконструктор
T>>полностью убрать, то всё работает

НС>Чего ж тут забавного? Объекты перестает держать fqueue и GC прекрасно справляется со сборкой.


вообще-то GC сам должен заглядывать во fqueue и всё там подчищать,
и если использовать больший массив _bytes = new byte[100000], то всё, как ожидается и работает,
если же взять _bytes = new byte[10000], то происходит outOfMemory
Re[4]: WPF. Финализаторы не вызываются. Утечка памяти
От: Ночной Смотрящий Россия  
Дата: 14.06.20 21:21
Оценка: +1
Здравствуйте, takTak, Вы писали:

T>вообще-то GC сам должен заглядывать во fqueue и всё там подчищать,


Он не может там подчистить без вызова финализаторов, а это потенциально долго.

T>и если использовать больший массив _bytes = new byte[100000], то всё, как ожидается и работает,


100К попадает в LOH, там несколько другие алгоритмы.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[2]: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 14.06.20 21:25
Оценка:
VC>

VC>а так?


IB>>
IB>>using System.Windows;

IB>>namespace ReproduceFinalizerMemoryLeak
IB>>{
IB>>    /// <summary>
IB>>    /// Interaction logic for MainWindow.xaml
IB>>    /// </summary>
IB>>    public partial class MainWindow : Window
IB>>    {
IB>>        public MainWindow()
IB>>        {
IB>>            do
IB>>            {
IB>>                TheMethod();
IB>>            } while (true);

IB>>            InitializeComponent();
IB>>        }
...

IB>>        ~Item()
IB>>        {

IB>>        }
IB>>    }
IB>>}
IB>>





не-а, это ничего не меняет... и с чего оно должно было бы измениться, здесь же не lambda-выражение\closure, а обычная локальная переменная


единственное, что всё меняет: это наличие или отсутствие деконструктора
Re[5]: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 14.06.20 21:29
Оценка:
T>>вообще-то GC сам должен заглядывать во fqueue и всё там подчищать,

НС>Он не может там подчистить без вызова финализаторов, а это потенциально долго.


если бы в Item не было вы массива, то всё бы тоже работало, даже с наследованием,
проблема в сочетании деконструктора и небольшого массива внутри объекта

T>>и если использовать больший массив _bytes = new byte[100000], то всё, как ожидается и работает,


НС>100К попадает в LOH, там несколько другие алгоритмы.


да, согласен, там другой алгоритм, и он справляется
Re[6]: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 14.06.20 21:43
Оценка:
T>>>вообще-то GC сам должен заглядывать во fqueue и всё там подчищать,

НС>>Он не может там подчистить без вызова финализаторов, а это потенциально долго.


T>если бы в Item не было вы массива, то всё бы тоже работало, даже с наследованием,

T>проблема в сочетании деконструктора и небольшого массива внутри объекта



не, даже без вложенного массива комбинация деконструктора и бесконечного цикла ведёт к outofmemory,
хотя в finalizer программа регулярно заходит
Re[3]: WPF. Финализаторы не вызываются. Утечка памяти
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.06.20 03:46
Оценка: +1
Здравствуйте, takTak, Вы писали:
T>единственное, что всё меняет: это наличие или отсутствие деконструктора
Деконструктор в дотнет — это метод Deconstruct. Он применяется для паттерн-матчинга и для деконструирующих присваиваний.
А то, о чём вы говорите, называется финализатором.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 15.06.20 06:30
Оценка:
T>>единственное, что всё меняет: это наличие или отсутствие деконструктора
S>Деконструктор в дотнет — это метод Deconstruct. Он применяется для паттерн-матчинга и для деконструирующих присваиваний.
S>А то, о чём вы говорите, называется финализатором.

забавно: в русском языке есть заимствовование "конструктор", так вот антонимом ему является не "деконструктор", а "деструктор",
"финализатор" на https://ru.wiktionary.org/ не находится
Re[5]: WPF. Финализаторы не вызываются. Утечка памяти
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.06.20 07:00
Оценка: +1
Здравствуйте, takTak, Вы писали:
T>забавно: в русском языке есть заимствовование "конструктор", так вот антонимом ему является не "деконструктор", а "деструктор",
T>"финализатор" на https://ru.wiktionary.org/ не находится
Мы говорим не о литературном русском языке, а о терминологии производителя. Деструкторов в CLR нет, т.к. деструктор подразумевает детерминистическую финализацию.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 15.06.20 07:15
Оценка:
T>>забавно: в русском языке есть заимствовование "конструктор", так вот антонимом ему является не "деконструктор", а "деструктор",
T>>"финализатор" на https://ru.wiktionary.org/ не находится
S>Мы говорим не о литературном русском языке, а о терминологии производителя. Деструкторов в CLR нет, т.к. деструктор подразумевает детерминистическую финализацию.


другие люди почему-то используют...
https://www.geeksforgeeks.org/destructors-in-c-sharp/

https://www.edureka.co/blog/destructor-in-java/

если обратно к нашим баранам, то
Use of finalize() methods should be avoided. They are not a reliable mechanism for resource clean up and it is possible to cause problems in the garbage collector by abusing them.
что мы, в принципе, на этом примере и видим
Re[6]: WPF. Финализаторы не вызываются. Утечка памяти
От: Ночной Смотрящий Россия  
Дата: 15.06.20 08:50
Оценка: +1
Здравствуйте, takTak, Вы писали:

T>проблема в сочетании деконструктора и небольшого массива внутри объекта


Нет. Проблема в большом количестве финализаторов и быстром выжирании пулов поколений.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[7]: WPF. Финализаторы не вызываются. Утечка памяти
От: takTak  
Дата: 15.06.20 09:17
Оценка:
T>>проблема в сочетании деконструктора и небольшого массива внутри объекта

НС>Нет. Проблема в большом количестве финализаторов и быстром выжирании пулов поколений.


ну да, похоже на такое...

как вообще происходит "быстрое выжирание пулов поколений" и почему gc.collect этому "выжиранию" препятствует?
Re[8]: WPF. Финализаторы не вызываются. Утечка памяти
От: Ночной Смотрящий Россия  
Дата: 15.06.20 09:41
Оценка:
Здравствуйте, takTak, Вы писали:

T>как вообще происходит "быстрое выжирание пулов поколений"


Путем быстрого выделения большого количества объектов.

T>и почему gc.collect этому "выжиранию" препятствует?


Потому что останавливает выделение и дает отработать финалайзерам.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.