编辑:问题与问题无关。我的代码确实有问题,实际上,它很简单,我不想把它放在互联网上。不管怎样,谢谢。
我读了大约550k的Active目录记录并将它们存储在List中,该类是AD用户的简单包装器。然后,我将ADRecords列表分成四个列表,每个列表包含总计的四分之一。在我这样做之后,我将数据库中的大约400k记录(称为EDR记录)读入DataTable。我占据了我的四个季度,并产生了四个线程,通过了四个季度中的每一个。我现在必须使用电子邮件将AD记录与EDR记录相匹配,但我们计划在以后添加更多内容以供匹配。
我在AD记录列表中有一个foreach,在其中,我必须在EDR记录上运行for循环来检查每个记录,因为如果AD记录匹配多个EDR记录,那么就是不是直接匹配,不应该被视为直接匹配。
我的问题,当我在列表中找到这个foreach时,我的ADRecords列表中只有大约130条记录,但是在我将它们全部拉入之后,我Console.WriteLine计数,它是544k。< / p>
我开始认为即使我没有将列表设置为null以便稍后收集,但是C#或Windows或其他东西实际上是我的列表,以便为EDR记录腾出空间,因为我没有使用过暂时列出一下。我必须用来读取EDR记录的数据库是一个链接服务器,因此全部读取它需要大约10分钟,因此我的列表实际上是空闲10分钟,但它永远不会设置为空。
有什么想法吗?
//splitting list and passing in values to threads.
List<ADRecord> adRecords = GetAllADRecords();
for (int i = 0; i < adRecords.Count/4; i++)
{
firstQuarter.Add(adRecords[i]);
}
for (int i = adRecords.Count/4; i < adRecords.Count/2; i++)
{
secondQuarter.Add(adRecords[i]);
}
for (int i = adRecords.Count/2; i < (adRecords.Count/4)*3; i++)
{
thirdQuarter.Add(adRecords[i]);
}
for (int i = (adRecords.Count/4)*3; i < adRecords.Count; i++)
{
fourthQuarter.Add(adRecords[i]);
}
DataTable edrRecordsTable = GetAllEDRRecords();
DataRow[] edrRecords = edrRecordsTable.Select("Email_Address is not null and Email_Address <> ''", "Email_Address");
Dictionary<string, int> letterPlaces = FindLetterPlaces(edrRecords);
Thread one = new Thread(delegate() { ProcessMatches(firstQuarter, edrRecords, letterPlaces); });
Thread two = new Thread(delegate() { ProcessMatches(secondQuarter, edrRecords, letterPlaces); });
Thread three = new Thread(delegate() { ProcessMatches(thirdQuarter, edrRecords, letterPlaces); });
Thread four = new Thread(delegate() { ProcessMatches(fourthQuarter, edrRecords, letterPlaces); });
one.Start();
two.Start();
three.Start();
four.Start();
在ProcessMatches中,传入的ADRecords列表中有一个foreach。foreach中的第一行是AdRecordsProcessed ++;这是一个全局静态int,程序在130而不是544k完成。
答案 0 :(得分:4)
变量永远不会设置为null并且仍在范围内?如果是这样,就不应该收集它,空闲时间不是你的问题。
我看到的第一个问题是:
AdRecordsProcessed++;
您在更新之前是否锁定了该全局变量?如果没有,并且取决于记录处理的速度,它将低于您的预期。
尝试从单个线程运行它(即传入adRecords而不是firstQuarter而不启动其他线程。)是否按预期使用1个线程?
答案 1 :(得分:2)
首先,您不要将列表设置为null。您可能要做的是将列表的每个引用设置为null(或另一个列表),或者所有此类引用可能只是超出范围。这可能看起来像是一个挑剔点,但如果你不得不检查你的数据发生了什么,那么就是时候对这些事情挑剔了。
其次,让GC取消分配具有实时引用的内容非常困难。您可以使用WeakReference&lt;&gt;伪造它或者当你在终结者中遇到一个错误时认为你已经找到了它(因为引用实际上并不存在,即使这样,它也是终结者试图处理最终化而不是解除分配对象的问题)。错误可能发生在任何地方,但是你已经找到了一种方法来让GC解除分配现状,这是非常不可能的。
GC可能会对您的列表做两件事:
除非你真正找到它们,否则这些都不会有任何你会发现的变化(显然你会注意到如果你继续调用GetGeneration()会产生一代变化,但除此之外你不会真正去)。
使用的内存也可以被分页,但是当你去使用这些对象时它会被重新分页。再一次,你不会注意到任何影响。
最后,如果GC确实释放了某些东西,你就不会有减少的项目数量,你就会崩溃,因为如果对象刚被解除分配,系统仍会尝试使用所谓的实时引用。
因此,虽然GC或操作系统可能会为您的其他对象腾出空间,但它不是代码中可观察到的东西,并且它不会阻止对象可用并处于相同的编程状态。
还有其他问题。
答案 2 :(得分:1)
您是否有必要同时获取所有数据?如果将数据分成块,它应该更易于管理。我所知道的只是进入GC的东西有点臭。最好看看重构代码。
答案 3 :(得分:1)
垃圾收集器不收集:
因此,如果您可以从代码中引用它,则垃圾收集器不可能收集它。没办法,没办法。
为了让收集者收集它,所有对它的引用都必须消失。如果你能看到它,那绝对不是这样的。