cch*_*ion 8 .net c# memory-management
我试图想出最简单的代码来重现我所看到的.完整的程序如下,但我将在此处进行描述.假设我的类命名ListData只有一些属性.然后假设我有一个MyList有成员的班级List<ListData> m_list.假设m_list在MyList构造函数中初始化.
在main方法中,我只需创建其中一个MyList对象,向其中添加一些对象ListData,然后让它超出范围.我在添加完成后在dotMemory中拍摄快照ListData,然后在MyList对象超出范围后再拍摄另一个快照.
在dotMemory中,我可以看到该MyList对象已按预期回收.我还看到ListData我创建的两个对象也按预期收回.
我不明白为什么有ListData[]幸存的?这是一个屏幕截图:

我在最新快照上打开幸存的对象,ListData[]然后我查看Key Retention Paths,这就是我所看到的.

我是.NET内存管理的新手,我创建了这个示例应用程序来帮助我探索它.我下载了JetBrains dotMemory版本4.3的试用版.我正在使用Visual Studio 2013 Professional.我必须学习内存管理,这样我才能解决我们工作中的内存问题.
这是完整的程序,可用于重现这一点.它只是一个快速而又脏的应用程序,但如果您对它进行分析,它会得到我要问的问题.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class ListData
{
public ListData(string name, int n) { Name = name; Num = n; }
public string Name { get; private set; }
public int Num { get; private set; }
}
class MyList
{
public MyList()
{
m = new List<ListData>();
}
public void AddString(ListData d)
{
m.Add(d);
}
private List<ListData> m;
}
class Program
{
static void Main(string[] args)
{
{
MyList l = new MyList();
bool bRunning = true;
while (bRunning)
{
Console.WriteLine("a or q");
string input = Console.ReadLine();
switch (input)
{
case "a":
{
Console.WriteLine("Name: ");
string strName = Console.ReadLine();
Console.WriteLine("Num: ");
string strNum = Console.ReadLine();
l.AddString(new ListData(strName, Convert.ToInt32(strNum)));
break;
}
case "q":
{
bRunning = false;
break;
}
}
}
}
Console.WriteLine("good bye");
Console.ReadLine();
}
}
}
Run Code Online (Sandbox Code Playgroud)
脚步:
请注意,MyList和两个ListData对象确实收集了垃圾,但ListData []却没有.为什么会有一个ListData []?如何让垃圾收集?
为什么有一个 ListData[] 挂在周围?我怎样才能让它被垃圾收集?
如果您查看 dotMemory 内的“创建堆栈跟踪”,您将看到:

这表明空ListData[0]实例是通过 的静态构造函数创建的List<T>。如果您查看源代码,您会看到以下内容:
static readonly T[] _emptyArray = new T[0];
Run Code Online (Sandbox Code Playgroud)
List<T>初始化默认的空数组以优化,避免每次创建新的List<T>. 这是默认构造函数:
public List()
{
_items = _emptyArray;
}
Run Code Online (Sandbox Code Playgroud)
只有你使用一个List<T>.Add,它才会调整数组的大小。
static成员从“高频堆”中引用,该堆为AppDomain应用程序中的每个成员创建一次。您看到的固定位置实际上是存储object[]所有实例的位置。static
由于实例是static,因此它将在应用程序的整个生命周期中保留在内存中。