3 / 3 / 2
Регистрация: 20.07.2014
Сообщений: 654
1

Убрать из памяти объект

24.01.2020, 00:18. Показов 5502. Ответов 15
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Есть объект в памяти

1 Класс
2 Массив
3 Метод
4 Инт какой-нибудь
5 И так далее


Как любое из этого списка освободить принудительно из памяти?
Как-то диспоузом что-ли?
Или он только для неуправляемых ресурсов сгодится?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
24.01.2020, 00:18
Ответы с готовыми решениями:

Как убрать из дочерних конкретный объект?
Простой 2d платформер, нужно, чтобы двигающаяся платформа делала игрока дочерним объектом, как он...

Не удаляется объект из памяти
Здравствуйте! У меня возникла следующая проблема: Мне нужно сделать форму, на которой бы...

Объект класса в динамической памяти
Привет. Вот листинг: #include <iostream> using namespace std; class SimpleCat { public:...

Получить объект по адресу в памяти
Здравствуйте! Как получить объект в (lldb) по его адресу в памяти? Через image lookup не получается...

15
Эксперт .NET
17751 / 12906 / 3374
Регистрация: 17.09.2011
Сообщений: 21,181
24.01.2020, 00:19 2
Цитата Сообщение от antoniogrid Посмотреть сообщение
Как любое из этого списка освободить принудительно из памяти?
Никак.
Можно принудительно вызвать сборщик и надеяться, что он подчистит объекты, на которые не осталось ссылок.
Но это тоже не гарантируется.

Цитата Сообщение от antoniogrid Посмотреть сообщение
Как-то диспоузом что-ли?
Или он только для неуправляемых ресурсов сгодится?
Да, только для неуправляемых.
1
3 / 3 / 2
Регистрация: 20.07.2014
Сообщений: 654
24.01.2020, 00:25  [ТС] 3
А если объект А ссылается на объект Б который ссылается на объект С, который ссылается на объект А.
Мы не сможем удалить объект А никогда, пока clr не завершит аппликейшен пул, в котором открыта программа?
0
Эксперт .NET
17751 / 12906 / 3374
Регистрация: 17.09.2011
Сообщений: 21,181
24.01.2020, 00:30 4
Цитата Сообщение от antoniogrid Посмотреть сообщение
Мы не сможем удалить объект А никогда, пока clr не завершит аппликейшен пул, в котором открыта программа?
Сможем, если до А нельзя добраться из "корневых" ссылок: в локальных переменных активных методов, регистров, статичкских переменных, СОМ-интеропа и пр.
Циклические ссылки не проблема.
1
3 / 3 / 2
Регистрация: 20.07.2014
Сообщений: 654
24.01.2020, 00:38  [ТС] 5
С этим, конечно, сложно.

Ну, я попробую после понять.


А если у нас делегат замкнул внешнюю переменную в лямбда выражении, которая суть анонимный метод, то мы не сможем убрать из памяти такую переменную, пока не финализируем делегат?
0
Эксперт .NET
17751 / 12906 / 3374
Регистрация: 17.09.2011
Сообщений: 21,181
24.01.2020, 00:44 6
antoniogrid, да, причем с захватом переменных все еще веселее, т.к. в некоторых случаях время ее жизни может зависеть от других делегатов, которые ее вообще не захватывали.
0
3 / 3 / 2
Регистрация: 20.07.2014
Сообщений: 654
24.01.2020, 00:50  [ТС] 7
Если можно, поподробнее хотя бы в теории, и как это?
0
Эксперт .NET
17751 / 12906 / 3374
Регистрация: 17.09.2011
Сообщений: 21,181
24.01.2020, 00:50 8
Цитата Сообщение от antoniogrid Посмотреть сообщение
поподробнее
Что именно?
0
3 / 3 / 2
Регистрация: 20.07.2014
Сообщений: 654
24.01.2020, 00:55  [ТС] 9
как может делегат, который не замыкал в себе переменную, мешать ее деаллокации?
она каким-то образом корнями связана с другим объектом, который ссылается на такой делегат?
почему такой посторонний для переменной делегат мешает очищению памяти от такой переменной?
как они связаны, как работает такое постороннее через что-то "замыкание", не могу понять
0
Эксперт .NET
17751 / 12906 / 3374
Регистрация: 17.09.2011
Сообщений: 21,181
24.01.2020, 01:18 10
antoniogrid, в майкрософтовском компиляторе имеется оптимизация, в которой для всех анонимных методов, созданных в одной области, используется один и тот же объект для хранения захваченных переменных — чтобы не плодить лишние объекты.
Как результат, если в одной области создается несколько анонимных методов, один из которых захватывает переменную, то время жизни этой переменной продляется до времени жизни самого долгоживущего из делегатов.

Экспонат раз:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
 
class Program
{
    static void Main()
    {
        var func = Bar();
 
        GC.Collect();
        GC.WaitForPendingFinalizers();
 
        Console.ReadKey();
        GC.KeepAlive(func);
    }
 
    static Func<int> Bar()
    {
        var foo = new Foo();
 
        int x = 42;
        Func<int> f = () => x;
 
        return f;
    }
}
 
class Foo
{
    ~Foo() => Console.WriteLine("Dead");
}
Метод Bar создает локальную переменную foo, потом захватывает локальную х анонимным методом и возвращает ссылку на его делегат.
Если запустить этот код, то в консоль выведется Dead, т.к. после завершения работы метода Bar на переменную foo не остается ссылок и сборщик ее убивает — что и будет продемонстрировано строкой "Dead" в консоли при запуске.

Экспонат два — все то же самое, но малость меняем реализацию метода Bar:
C#
1
2
3
4
5
6
7
8
9
static Func<int> Bar()
{
    var foo = new Foo();
    Action a = () => Console.WriteLine(foo);
 
    int x = 42;
    Func<int> f = () => x;
    return f;
}
Теперь в методе Bar дополнительно создается анонимный метод a, захватывающий переменную foo.
Ссылка на этот делегат никуда не возвращается и по завершении работы метода делегат, захвативший переменную foo, может быть удален сборщиком.

Однако, в этой же области был создан и делегат f, который захватил совсем другую переменную, но из-за вышеупомянутой оптимизации оба делегата используют один и тот же объект для захвата, а значит foo может быть удалена сборщиком только тогда, когда могут быть удалены и a, и f.
Последний сможет быть удален только по завершении работы метода Main — ссылка на него возвращается методом Bar и присваивается переменной func в Main, а значит вывод в консоль Dead вы можете не увидеть до самого окончания работы программы.

Этот сценарий, кстати, является одним из самых распространенных причин утечки памяти.
Особенно легко на него попасть при яром использовании Linq, где переменные захватываются налево и направо.
Так что будьте осторожны.
4
3 / 3 / 2
Регистрация: 20.07.2014
Сообщений: 654
24.01.2020, 03:20  [ТС] 11
Пока тупым себя ощущаю, но попробую продвинуться.

1. Как я понимаю, CLR аллоцирует объект hash таблицы, где расположены ссылки на все анонимные методы, задействованные вследствие компиляции определенной программы.
2. Не важно, включены ли данные анонимные методы в делегат или используются вне них.
3. Так же в этой hash таблице находятся ссылки на переменные, захваченные в эти анонимные методы. Весь этот объект хранится в куче.
4. Это единый объект в виде hash таблицы в памяти, на который, насколько я понимаю, CLR еще и хранит ссылку в finalization queue. Просто потому что в целях оптимизации в случае необходимости финализировать все анонимные методы это лучше будет сделать за один раз целиком, передавая ссылки на все эти методы одной ссылкой на объект hash таблицы в freacheable queue. Соответственно, уничтожая все ссылки анонимных методов уничтожением объекта hash таблицы за один раз.
5. В одном из анонимных методов у нас замкнулась переменная. В остальных нет. Однако остальные анонимные методы имеют корневые ссылки на другие объекты и могут пережить сборку мусора.
6. Таким образом эти остальные анонимные методы, цепляясь корнями за другие объекты, не дают CLR осуществить перемещение ссылки hash таблицы из finalization queue в freacheable queue, с замкнувшим переменную анонимным методом, хотя пора бы уже данный делегат с его методом, утратившим корни - убить.
7. В итоге у нас долгоиграющая замкнутая переменная, хотя и нету корней в замкнувшем ее делегате. И мемори лик.

А Linq при использовании лямбда выражений замыкает данные из источника данных(базы данных, файлы XML, объекты(массивы))
Хотя мы и оборачиваем запросы Linq в using - не факт, что финализация таких неуправляемых соединений будет происходить по причине наличия оптимизации в CLR. По крайней мере, мы не сможем удалить полученные методом расширения из базы данных замкнутые в лямбда "переменные" до тех пор, пока делаем другие запросы к базе данных и пока приложение не выгрузится из application pool? Такая ситуация, возможно, бывает, когда у нас происходит, несколько запросов к базе данных через Linq и один из них еще получает данных из базы, а другой уже завершился, но не может быть финализирован, потому что другой запрос Linq еще открыт и получает данные из базы? Это типа, может быть такой небольшой dead lock? Пока один анонимный метод будет ожидать завершение другого? Но в итоге, они все благополучно завершаться же, так как каждый из них мы их обернули в using.
И вроде, ничего страшного нет, если за этим все хорошо следить и все оборачивать. Впрочем, Linq где нибудь в другой части кодовой базы, в другом файле, который мы не видим, действительно, один раз отработав, может подвесить финализацию всех соединений вплоть до пока приложение не выгрузиться из Application pool?
0
Эксперт .NET
17751 / 12906 / 3374
Регистрация: 17.09.2011
Сообщений: 21,181
24.01.2020, 15:00 12
Цитата Сообщение от antoniogrid Посмотреть сообщение
Как я понимаю, CLR аллоцирует объект hash таблицы, где расположены ссылки на все анонимные методы, задействованные вследствие компиляции определенной программы.
Нет, хэш-таблица не создается.
Создается простой объект анонимного типа, в котором реализован ваш "анонимный" метод и локальные переменные представлены полями.
0
3 / 3 / 2
Регистрация: 20.07.2014
Сообщений: 654
24.01.2020, 15:12  [ТС] 13
Ок, объект анонимного типа. В нем 45 переменных из 45 анонимных методов. Как CLR тогда находит свою переменную для своего метода?

Добавлено через 3 минуты
Ну, вообще, принцип я понял.

У меня вопрос по Linq интересует, можно ли подробнее объяснить, в какой ситуации будет мемори лик при использовании Linq, если мы его не обернули в using?
0
Эксперт .NET
17751 / 12906 / 3374
Регистрация: 17.09.2011
Сообщений: 21,181
24.01.2020, 16:44 14
Цитата Сообщение от antoniogrid Посмотреть сообщение
Как CLR тогда находит свою переменную для своего метода?
Так же, как вы находите нужное вам поле класса в методе этого поля — путем обращения к этому полю.

Цитата Сообщение от antoniogrid Посмотреть сообщение
какой ситуации будет мемори лик при использовании Linq, если мы его не обернули в using?
Как это: обернуть Linq в using?
0
Модератор
Эксперт .NET
15661 / 10843 / 2812
Регистрация: 21.04.2018
Сообщений: 31,844
Записей в блоге: 2
24.01.2020, 18:19 15

Не по теме:

Цитата Сообщение от kolorotur Посмотреть сообщение
Как это: обернуть Linq в using?
Я думал, я один такой непонимающий...

0
3 / 3 / 2
Регистрация: 20.07.2014
Сообщений: 654
24.01.2020, 18:22  [ТС] 16
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
        [HttpGet]
        public ActionResult AddOrEditPhone(int id = 0)
        {
            if (id == 0)
                return View(new Phone());
            else
            {
                using (AppEntities db = new AppEntities())
                {
                    return View(db.Phones.Where(x => x.PhoneID == id).FirstOrDefault<Phone>());
                }
            }
        }

Я в этом смысле
0
24.01.2020, 18:22
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.01.2020, 18:22
Помогаю со студенческими работами здесь

Создание указателя на объект и выделение памяти
Не пойму почему при добавлении одного указателя выдает ошибку Этот код работает class A {...

4 раза в памяти создается объект класса
Доброго времени суток! Есть следующий код: #include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include...

Выделение памяти под новый объект
Люди, посоветуйте, пожайлуста, как в уже созданный массив из N объектов добавить ещё один объект?...

Динамическое выделение памяти под объект
Здравствуйте, меня интересует несколько вопросов по поводу конструкции new. Есть такой код: ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru