我在c#windows服务中有一个巨大的数据集,它使用大约12GB的内存。
Dictionary<DateTime,List<List<Item>>>
添加了不断的新数据流,每小时约1GB。旧数据偶尔会被删除。这是一个用于网页的高速缓冲区。
我在配置文件中有一个名为“MaxSizeMB”的参数。我想允许用户输入,比如“11000”,我的应用程序将在每次应用超过11GB的ram使用时删除一些旧数据。
事实证明这令人沮丧。
你会认为你可以调用GC.GetTotalMemory(false)。这将为您提供.net托管对象的内存使用(假设它的内容为10.8GB)。然后你只需要为应用程序中分配的所有其他东西添加一个200MB的常量安全网。
这不起作用。实际上,加载的数据越多,GC.GetTotalMemory和任务管理器之间的差异就越大。我甚至尝试计算出一个常数乘数值而不是一个常数加值,但我无法得到一致的结果。到目前为止,我所做的最好的事情是计算数据结构中的项目总数,乘以96,并假设该数字是ram使用情况。这也令人困惑,因为Item对象是一个32byte的结构。这种假装的ram使用也太不稳定了。有时该应用程序将删除11GB的旧数据,但有时会删除8GB ram使用的数据,因为我假装的数字计算错误的11GB。
所以我可以使用这种保守的假ram计算,并且经常不使用我允许使用的所有ram(比如丢失2GB),或者我可以使用GC.GetTotalMemory而且客户会觉得应用程序结束了偶尔设置ram。
有没有办法在不超出限制的情况下尽可能多地使用ram,因为它出现在任务管理器中?我不在乎数学是乘数,不变增值,功率等等。我希望在达到最大设置时将数据填充到数据结构中并删除数据。
注意:我已经做了一些内存缩小技术,例如使用struct作为Item,list.Capacity = list.Count和GC.Collect(GC.MaxGeneration)。这些似乎是一个单独的问题。
答案 0 :(得分:2)
使用System.Diagnostics.PerformanceCounter
并监控您当前的进程内存使用情况和可用内存,根据此情况,您的应用程序应决定是否删除某些内容。
答案 1 :(得分:2)
答案非常简单。
var n0 = System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64;
var n1 = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64;
var n2 = System.Diagnostics.Process.GetCurrentProcess().VirtualMemorySize64;
float f0 = ((float)n0)/(1000*1000);
float f1 = ((float)n1)/(1000*1000);
float f2 = ((float)n2)/(1000*1000);
Console.WriteLine("private = " + f0 + " MB");
Console.WriteLine("working = " + f1 + " MB");
Console.WriteLine("virtual = " + f2 + " MB");
结果:
private = 931.9096 MB
working = 722.0756 MB
virtual = 1767.146 MB
所有这些关于任务管理器和.net对象大小的呻吟和烦恼以及答案是在一行代码中构建到.NET中的。
我给了Sarvesh一个答案,因为他让我使用PerformanceCounter开始了正确的道路,但GetCurrentProcess()结果是一个很好的捷径来简单地检查你自己的过程。
答案 2 :(得分:1)
几个问题
垃圾收集
获得良好的记忆力量
什么是最大值
您认为存在最大硬度。 但是一个对象需要连续的内存,因此它是一个软的最大值。
对于准确的尺寸测量,您可以记录每个列表的大小并保持运行总计 然后,当您清除读取大小并从该运行总计中减少时。
为什么要对抗.NET内存限制和物理内存限制 我会选择SSD上的数据库 如果它是只读的并且您已知类,则可以像RavenDB一样使用 重新考虑你的设计
好的,所以我对管理.NET内存限制没有太大的帮助,你永远不会驯服。
仍在重新考虑你的设计。
如果您的PK是一个DateTime并且假设您每小时只需要24小时,那么这只是一个对象
在23小时结束时新的先前 - 让GC收集整个事情。