Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
1

А будет ли сборка мусора?

15.04.2018, 11:43. Показов 615. Ответов 13

Author24 — интернет-сервис помощи студентам
Всем привет!

Посмотрите внимательно на следующий код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
namespace Temp
{
   public class Program
   {
      public static void Main(string[] args)
      {
         SomeEnum a = SomeEnum.a;
         SomeEnum b = SomeEnum.b;
         while(true)
         {
            bool res = a.Equals(b);
         }
      }
 
      public enum SomeEnum
      {
         a,
         b,
      }
   }
}
И ответьте на три вопроса:
  1. Будет ли этот код инициализировать сборку мусора поколения 0?
    Если будет, то почему? Если не будет, то почему?

  2. А будет ли сборка мусора поколения 1? Тоже обосновать.

  3. А как насчёт сборки поколения 2? Обосновать.

Не по теме:

Для честности код не тестить. only for fans.

0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.04.2018, 11:43
Ответы с готовыми решениями:

Сборка мусора
Сейчас читаю книгу "Pro C# 5.0 and the .NET 4.5 Framework" - Andrew Troelsen. Дошел до главы о...

Сборка мусора
Доброе время суток Есть такой вопрос, касающийся сборки мусора. Если два объекта (или более,...

Сборка мусора .NET
У меня такой вопрос. class First { Second ob = new Second(); ~First() ...

Сборка мусора
Здравствуйте. Есть список, который постоянно пополняется новыми строчками. Строчек очень много...

13
Эксперт .NET
6452 / 4053 / 1599
Регистрация: 09.05.2015
Сообщений: 9,487
15.04.2018, 12:14 2
А что тут собирать то? Value type который вы на стэке создали? Собирать нечего, соответственно никакой сборки мусора не будет.
1
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
15.04.2018, 12:19  [ТС] 3
Цитата Сообщение от Someone007 Посмотреть сообщение
А что тут собирать то? Value type который вы на стэке создали?
То есть ваш ответ: сборок мусора не будет вообще. Окей.
0
447 / 305 / 47
Регистрация: 23.01.2013
Сообщений: 661
15.04.2018, 12:29 4
Если там метод object.Equals(object obj), то конечно будет, ведь перечисление это значимый тип, и он будет упакован. Но только для 0 поколения, т.к. результирующие упакованные структуры никто не держит, и они не будут примерещатся на поколение выше.
1
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
15.04.2018, 12:34  [ТС] 5
Цитата Сообщение от Anklav Посмотреть сообщение
Но только для 0 поколения, т.к. результирующие упакованные структуры никто не держит, и они не будут примерещатся на поколение выше.
Ваш ответ: сборка только для поколения 0. Окей.
Кто даст больше?!
0
Anklav
15.04.2018, 12:37
  #6

Не по теме:


Цитата Сообщение от Fleder Посмотреть сообщение
Кто даст больше?!
Вы пожалуйста поаккуратнее с такими восклицаниями, я например воспринимаю это как троллинг.

0
1144 / 853 / 262
Регистрация: 30.04.2009
Сообщений: 3,581
15.04.2018, 12:43 7
При вызове метода Equals происходит boxing значения enum-а, так что обьекты в куче будут создаваться.
Сборка мусора будет запущена, когда этих обьектов насобирается много, в соответствии с текущим GC memory threshold.
В 99.99% случаев эти обьекты не переживут 0-е поколение и будут сразу собраны, т.к. ссылки на них существуют только при выполнении метода Equals.
Если GC запущен во время выполнения метода Equals, то boxed обьект перейдет в поколение 1.
Перейти в поколение 2 шансов нет.
Сборка поколений 1, 2 будет происходить в соответствии с обычным регламентом (в поколение 2 попадет обьект args).
1
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
15.04.2018, 13:54  [ТС] 8

Не по теме:

Цитата Сообщение от Anklav Посмотреть сообщение
Вы пожалуйста поаккуратнее с такими восклицаниями, я например воспринимаю это как троллинг.
Извините.



Добавлено через 38 минут
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Если GC запущен во время выполнения метода Equals, то boxed обьект перейдет в поколение 1.
То есть, боксим объект 1, боксим объект 2 и вызываем для них Equals.
Если первый бокс влез в эфемерную кучу, а для второго места не хватило, то первый бокс перейдёт в поколение 1. Так?

Цитата Сообщение от nicolas2008 Посмотреть сообщение
В 99.99% случаев эти обьекты не переживут 0-е поколение и будут сразу собраны
Похоже на то, что процент вероятности пережить сборку поколения 0 выше, чем 0.01%,
потому что вот этот код тоже вызывает сборку для поколения 1:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
 
namespace Temp
{
   public class Program
   {
      public static void Main(string[] args)
      {
         int n = 10;
         object obj;
         while(true)
         {
            obj = n;
         }
         GC.KeepAlive(obj);
      }
   }
}
Каким образом на момент боксинга удерживается ссылка на предыдущий боксинг - непонятно.
Наверное, она в регистрах как-то сохраняется.
0
1144 / 853 / 262
Регистрация: 30.04.2009
Сообщений: 3,581
15.04.2018, 14:49 9
Цитата Сообщение от Fleder Посмотреть сообщение
То есть, боксим объект 1, боксим объект 2 и вызываем для них Equals.
Если первый бокс влез в эфемерную кучу, а для второго места не хватило, то первый бокс перейдёт в поколение 1. Так?
Хм... первый не перейдет, т.к. на него уже нет ссылки (ввиду специфики кода в примере), а второй я думаю может перейти в поколение 1.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
enum MyEnum
        {
            Value1,
            Value2
        }
 
        static void Main(string[] args)
        {
            MyEnum x = MyEnum.Value1;
            TestMethodWithBoxing(x);
            Console.ReadLine();
        }
 
        private static void TestMethodWithBoxing(object obj)
        {
            Console.WriteLine("Generation of obj is " + GC.GetGeneration(obj)); // 0
            // simulating GC Collect event while method is being executed
            GC.Collect();
            Console.WriteLine("Generation of obj is " + GC.GetGeneration(obj)); // 1
        }
Цитата Сообщение от Fleder Посмотреть сообщение
Похоже на то, что процент вероятности пережить сборку поколения 0 выше, чем 0.01%,
потому что вот этот код тоже вызывает сборку для поколения 1:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
namespace Temp
{
 public class Program
 {
 public static void Main(string[] args)
 {
 int n = 10;
 object obj;
 while(true)
 {
 obj = n;
 }
 GC.KeepAlive(obj);
 }
 }
}
Каким образом на момент боксинга удерживается ссылка на предыдущий боксинг - непонятно.
Наверное, она в регистрах как-то сохраняется.
Не совсем понимаю откуда такие выводы.
0
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
15.04.2018, 15:11  [ТС] 10
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Не совсем понимаю откуда такие выводы.
Этот код должен упасть после хотя бы одной сборки поколения 1. У меня это происходит при count = 274903373 и Gen0 = 3222
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
using System;
 
namespace Temp
{
   public class Program
   {
      public static void Main(string[] args)
      {
         long count = 0;
         int n = 10;
         object obj;
         while(true)
         {
            obj = n;
            ++count;
            if(GC.CollectionCount(1) > 0)
            {
               throw new Exception($"Gen0 = {GC.CollectionCount(0)}, count = {count}");
            }
         }
         GC.KeepAlive(obj);
      }
   }
}
0
1144 / 853 / 262
Регистрация: 30.04.2009
Сообщений: 3,581
15.04.2018, 16:08 11
Цитата Сообщение от Fleder Посмотреть сообщение
Этот код должен упасть после хотя бы одной сборки поколения 1. У меня это происходит при count = 274903373 и Gen0 = 3222

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
namespace Temp
{
 public class Program
 {
 public static void Main(string[] args)
 {
 long count = 0;
 int n = 10;
 object obj;
 while(true)
 {
 obj = n;
 ++count;
 if(GC.CollectionCount(1) > 0)
 {
 throw new Exception($"Gen0 = {GC.CollectionCount(0)}, count = {count}");
 }
 }
 GC.KeepAlive(obj);
 }
 }
}
Уже понятнее, но как по мне методика вычисления непрозрачная.
Вот что получилось у меня, старался делать максимально приближенно к примеру:

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
        enum MyEnum
        {
            Value1,
            Value2
        }
 
        static void Main(string[] args)
        {
            MyEnum x = MyEnum.Value1;
            int iter = 0;
 
            while (true)
            {
                iter++;
 
                WeakReference xwh = TestMethodWithBoxing(x);
 
                int gen = GC.GetGeneration(xwh.Target);
                if (xwh.IsAlive && gen > 0)
                {
                    Console.WriteLine($"Boxed object is in Gen {gen} (on iteration {iter} (with probability of {100m/iter:0.000000} %))");
                    iter = 0;
                }
            }
        }
 
        private static WeakReference TestMethodWithBoxing(object obj)
        {
            return new WeakReference(obj);
        }
Boxed object is in Gen 1 (on iteration 87358 (with probability of 0,001145 %))

Добавлено через 22 минуты
new WeakReference тоже создают обьекты в куче, так что тест получился плохой.

Обновленный тест, похоже obj никогда не попадает в Gen 1.

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
31
32
enum MyEnum
        {
            Value1,
            Value2
        }
 
        static void Main(string[] args)
        {
            MyEnum x = MyEnum.Value1;
            while (true)
            {
                checked
                {
                    iter++;
                }
                TestMethodWithBoxing(x);
            }
        }
 
        private static int iter = 0;
 
        private static void TestMethodWithBoxing(object obj)
        {
            // simulate equals method
            bool result = obj is MyEnum @enum && MyEnum.Value1 == @enum;
 
            int gen = GC.GetGeneration(obj);
            if (gen > 0)
            {
                Console.WriteLine($"Boxed object is in Gen {gen} (on iteration {iter} (with probability of {100m/iter:0.000000} %))");
            }
        }
0
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
15.04.2018, 16:59  [ТС] 12
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Обновленный тест, похоже obj никогда не попадает в Gen 1.
Но какие-то объекты всё равно проникают в поколение 1.
Это видно в средствах диагностики Visual Studio (оранжевая галочка появляется)
или можно вставить блок проверки на основе if(GC.CollectionCount(1) > 0) в
цикл. Исключение появится там же, где и галочка.

Добавлено через 35 минут
nicolas2008, вот попытался вынести боксинг из цикла, чтоб не инлайнился.
Но результат всё тот же: поколение 1 наполняется непонятно какими объектами.
А "свежеупакованное" значение всегда в поколении 0.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using System.Runtime.CompilerServices;
 
namespace Temp
{
   public class Program
   {
      public static void Main(string[] args)
      {
         long count = 0;
         int n1 = 10;
         while(true)
         {
            int n2 = Boxing(n1);
            ++count;
            if(GC.CollectionCount(1) > 0)
            {
               //Падаем тут
               throw new Exception($"Gen0 = {GC.CollectionCount(0)}, count = {count}");
            }
         }
      }
 
      [MethodImpl(MethodImplOptions.NoInlining)]
      public static int Boxing(int n)
      {
         object obj = n;
         if(GC.GetGeneration(obj) != 0)
         {
            //Это исключение не бросается
            throw new Exception();
         }
         //без этого костыля компилятор вырезает боксинг и возвращает напрямую параметр n
         return (int)Transited(obj);
      }
 
      [MethodImpl(MethodImplOptions.NoInlining)]
      public static object Transited(object obj)
      {
         return obj;
      }
   }
}
Создаётся впечатление, что при использовании памяти из управляемой кучи ограничиться только нулевым поколением
в принципе невозможно.
0
1144 / 853 / 262
Регистрация: 30.04.2009
Сообщений: 3,581
15.04.2018, 17:19 13
Цитата Сообщение от Fleder Посмотреть сообщение
Но какие-то объекты всё равно проникают в поколение 1.
Это видно в средствах диагностики Visual Studio (оранжевая галочка появляется)
или можно вставить блок проверки на основе if(GC.CollectionCount(1) > 0) в
цикл. Исключение появится там же, где и галочка.
Какие то проникают, но я думаю что это другие обьекти, пока не доказано обратное
Сделай Performance Profiler-ом Memory Snapshot и увидишь, что там куча разных системных обьектов.
0
447 / 305 / 47
Регистрация: 23.01.2013
Сообщений: 661
15.04.2018, 17:22 14
Так а вы думаете что кроме ваших объектов там больше ничего нету?
Там же куча статических ссылок, да тот же AppDomain и Thread.
Я думаю время от времени сборщик мусора все же обязан убирать в остальных поколениях, даже если они не достигли предела. Хотя бы для того, что бы более менее вовремя вызывать финализаторы.
0
15.04.2018, 17:22
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
15.04.2018, 17:22
Помогаю со студенческими работами здесь

Сборка мусора
Всем доброго времени суток. Подскажите. Как часто приходится писать деструкторы, реализовать...

Сборка мусора
Рассмотрим следующий случай. В программе было создано два объекта разных классов. Причем первый...

Сборка мусора
Синтаксис C# предлагает синонимичную конструкцию для автоматического вызова метода Dispose -...

Сборка мусора вручную
Можно ли принудительно собирать мусор вручную? Как я понимаю можно с помощью GC.Collect, а если...


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

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