На работе появилась задача раскопать завалы, лежащие в LOH. После некоторых попыток я обнаружил непонятное для себя поведение GC:
public class Program
{
public static void Test()
{
List<int> list = new List<int>(1000000000);
list = null;
GC.Collect();
}
public static void Main(string[] args)
{
Test();
for (long i = 0; i < 100000000000; i++)
{
string temp = new string(new char[] { 'a', 'b', 'c' });
}
}
}
В таком виде сборщик мусора срабатывает, но не очищает выделенную память под List даже при условии, что на него ничего не ссылается. Даже больше - она не очистится даже после периодической сборке мусора в цикле.
Если же удалить строчку с форсированным вызовом GC, то память очистится практически сразу, когда в цикле потребуется выделить новую. В чем дело?
Дополняю вопрос:
Если переписать код вот так:
public class Program
{
public static void Test()
{
List<int> list = new List<int>(1000000000);
list = null;
}
public static void Main(string[] args)
{
Test();
GC.Collect();
for (long i = 0; i < 100000000000; i++)
{
string temp = new string(new char[] { 'a', 'b', 'c' });
}
}
}
То очистка list не произойдет при первом вызове GC.Collect, она произойдет при втором (автоматическом) вызове сборщика внутри цикла for.
А если написать вот так:
public class Program
{
public static void Test()
{
List<int> list = new List<int>(1000000000);
list = null;
}
public static void Main(string[] args)
{
Test();
GC.Collect();
while (true) ;
}
}
То list не очистится вовсе. Честно говоря, это также вгоняет меня в ступор.
GCSettings.LargeObjectHeapCompactionMode пробовал менять на CompactOnce, также пробовал GC.Collect(2), эффект тот же.