【发布时间】:2015-12-26 00:03:33
【问题描述】:
我有一个我一直在研究的数据解析应用程序,考虑到它正在读取的文本文件的绝对大小,控制内存使用是获得良好性能的关键。这里的两部分策略首先测量每个文件对总和的贡献有多少 RAM,但它还需要知道在给定时间点应用程序有多少 RAM 可用。如果有足够的 RAM 可用,应用程序会选择在内存中进行处理。否则,它会切换到在磁盘上执行所有或大部分操作的模式。
测量文件对内存使用的贡献既快捷又简单:
static Int64 GetSizeInMemory(string path)
{
//THIS CODE IS SPEEDY
Int64 r = ((Func<Int64>)(
() =>
{
try
{
using (Stream s = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(s, File.ReadAllLines(path));
return s.Length;
}
}
catch
{
//this file is way too big
return -1;
}
}
))();
GC.Collect();
GC.WaitForPendingFinalizers();
return r;
}
但是,测量可用内存总量既慢又困难。在这种情况下,我试图通过捕获堆栈溢出错误来做到这一点,在我看来,这应该给出最可靠的数字。
static Int64 GetMaxAllowedMemory()
{
//THIS CODE IS SLOW
Int64 r = ((Func<Int64>)(
() =>
{
byte[] b = new byte[]{};
Int64 rs = 0;
while (true)
{
try
{
Array.Resize<byte>(ref b, b.Length + 1);
b[b.Length - 1] = new byte();
rs = b.Length;
} catch (Exception e) {
break;
}
}
b = null;
return rs;
}
))();
GC.Collect();
GC.WaitForPendingFinalizers();
return r;
}
我应该在这里使用更好的方法吗?
请注意我在 Stack Overflow 上查看了许多与此类似的问题,但大多数问题仅涉及获取计算机上可用 RAM 总量的数字,这不是与 .NET 进程在运行时允许的最大 RAM 量相同。
更新
收到答复后,我想出了以下方法,可让我获得应用程序可用的 RAM 总量。
static Int64 GetMemoryFailPoint()
{
Int64 r = ((Func<Int64>)(
() =>
{
int rs = 1;
while (true)
{
try
{
using (new System.Runtime.MemoryFailPoint(rs))
{
}
}
catch {
break;
}
rs++;
}
return Convert.ToInt64(rs) * 1000000;
}
))();
return r;
}
【问题讨论】:
-
对于您的更新,您可能可以通过将值加倍直到失败然后除以 2 并在该点之后缓慢上升来使您的代码更快。此外,根据the remarks section of the documentation “MemoryFailPoint 以 16 MB 的粒度运行。任何小于 16 MB 的值都被视为 16 MB,其他值被视为 16 MB 的下一个最大倍数” 所以
rs++应该是rs += 16,你正在做 15 次额外的检查,将返回相同的结果。 -
最后,一个 MB 中有
1 << 20(1048576) 字节,所以你的回报应该是return Convert.ToInt64(rs) * (1 << 20);。对于 2048 MB (2GB),这将是 99,483,648 字节的差异。 -
@ScottChamberlain 谢谢!我一定会考虑的。另外,关于返回的指针是最有帮助的。
标签: c# memory-management