什么是一些提示,以减少.NET应用程序的内存使用情况? 考虑下面简单的C#程序。
class Program
{
static void Main(string[] args)
{
Console.ReadLine();
}
}
在释放模式编译为64位和Visual Studio外运行,任务管理器报告如下:
Working Set: 9364k
Private Working Set: 2500k
Commit Size: 17480k
这是一个好一点,如果它只是编译为86:
Working Set: 5888k
Private Working Set: 1280k
Commit Size: 7012k
然后,我尝试下面的程序,它不相同,但试图运行时初始化后修剪过程尺寸:
class Program
{
static void Main(string[] args)
{
minimizeMemory();
Console.ReadLine();
}
private static void minimizeMemory()
{
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle,
(UIntPtr) 0xFFFFFFFF, (UIntPtr)0xFFFFFFFF);
}
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetProcessWorkingSetSize(IntPtr process,
UIntPtr minimumWorkingSetSize, UIntPtr maximumWorkingSetSize);
}
在Visual Studio的外面86 公布结果:
Working Set: 2300k
Private Working Set: 964k
Commit Size: 8408k
这是一个好一点,但它似乎仍然过大这样一个简单的程序。 是否有任何技巧,使一个C#程序有点精简? 我写它的设计,以在后台运行的大部分时间的程序。 我已经在做一个单独的任何用户界面的东西应用领域 ,这意味着用户界面的东西可以安全地卸载,但占用10 MB,当它只是坐在后台似乎过高。
PS至于为什么我会在意---(电源)的用户往往担心这些事情。 即使对性能几乎没有影响,半精通技术的用户(我的目标受众)往往进入嘘声像符合有关后台应用程序的内存使用情况。 即使我发疯,当我看到的Adobe更新程序以11 MB的内存,并感到平静触摸的Foobar2000,它可以播放,即使在6 MB需要安慰。 我知道,在现代的操作系统,这个东西其实并不重要,那么多技术,但是,这并不意味着它不会对感知的影响。
- 你可能想看看堆栈溢出问题.NET EXE内存占用 。
- MSDN博客文章工作集!=实际内存占用是所有关于神秘化工作集,进程内存和如何在总的-RAM消费进行精确的计算。
我不会说你应该忽略你的应用程序的内存占用量 - 显然,体积更小,效率也往往是可取的。 但是,你应该考虑你的实际需求是什么。
如果你正在写一个标准的Windows窗体和WPF客户端应用程序这是注定要一个人的PC上运行,并且很可能是在用户操作的主要应用程序,你可以逃脱更加无精打采的约内存分配。 (只要这一切被释放。)
然而,为了解决这里的一些人谁说不担心:如果你正在编写一个Windows窗体应用程序,这将在终端服务环境中运行,可能10,20或更多的用户,然后使用一个共享的服务器上是,你绝对必须考虑内存使用情况。 你会需要警惕。 解决这一问题的最好办法是具有良好的数据结构设计,并通过以下时,哪些是你分配有关最佳做法。
相比由于它们都必须加载运行,并在这个过程中应用程序的本地应用程序的.NET应用程序将有一个更大的足迹。 如果你想获得真正的整洁,.NET未必是最好的选择。
但是,请记住,如果你的应用程序主要是睡觉,必要的内存页面将被换出的内存中,因此不会真的是那么多的系统的负担,在大的大部分时间。
如果你想保持足迹小,你将不得不考虑一下内存的使用情况。 这里有几个想法:
- 减少对象的数量,并确保没有扶住长于所需的任何实例。
- 要注意的
List<T>
和相似类型的需要时,他们可能会导致高达50%的废物产能翻番。 - 你可以考虑使用值类型在引用类型强制在堆栈上更多的内存,但请记住,默认的栈空间只有1 MB。
- 避免超过85000个字节的对象,因为他们会去LOH这不板结,因而可以很容易地得到分散。
这可能是不以任何方式详尽的清单,但只是一对夫妇的想法。
你需要在这种情况下,要考虑的一件事是CLR的存储成本。 在CLR被加载为每净过程,因此因子到存储器的考虑。 对于这样一个简单/小程序的CLR的费用将主宰你的内存占用。
这将是更有益的构建一个真正的应用程序和浏览相比,该基线方案的费用,该费用。
本身没有具体的建议,但你可能需要看看CLR分析器 (从微软免费下载)。
一旦你已经安装了它,看看这如何做网页 。
从操作方法:
该如何向您展示如何使用CLR Profiler工具来调查你的应用程序的内存分配方案。 您可以使用CLR分析器,以确定导致记忆问题,如内存泄漏和过度的或低效的垃圾收集代码。
可能想看看一个“真正的”应用程序的内存使用情况。
与Java类似有开销来运行一些固定的金额,无论程序的大小,但内存消耗将在该点之后更合理。
有许多方法来减少你的足迹。
有一件事你会永远拥有与居住.NET是你的IL代码的本机图像的大小是巨大的
而这种代码不能完全应用实例之间共享。 即使NGEN'ed组件是不完全静态的,他们仍然需要JITting一些小的部分。
人们也往往会编写代码块的内存比需要更长的时间。
一个经常看到的例子:以一个DataReader,加载内容到一个DataTable只是它被写入到一个XML文件中。 你可以很容易碰到一个OutOfMemoryException。 OTOH,你可以使用一个XmlTextWriter并通过DataReader的滚动,发射将XMLNode你通过数据库光标滚动。 这样一来,你只需要在当前的数据库记录,并在内存中的XML输出。 这永远不会(或不可能)获得较高的垃圾回收发电,因此可重复使用。
这同样适用于获得一些实例列表,做一些东西(即产卵的数千名新的情况下,这可能会保持某个地方在引用的),即使你不需要他们之后,你还是引用的一切,直到在foreach后。 明确是NULL-ING您的输入列表和临时副产品的手段,这种内存可以退出你的循环,甚至之前被重用。
C#有一个叫做迭代一个极好的功能。 它们允许你通过你的输入滚动到流对象,只保留当前的情况下,直到你下一个。 即使是使用LINQ,你还不需要让所有的它周围只是因为你希望它进行过滤。
解决的称号,而不是具体问题的一般性问题:
如果您使用的是返回大量数据的COM组件(说双打的大2×N个阵列),只需要一小部分,然后就可以编写从.NET和返回这是唯一的数据隐藏了内存的包装COM组件需要。
这就是我在主应用程序没有和它显著提高了内存消耗。
我发现,使用SetProcessWorkingSetSize或EmptyWorkingSet API来定期强制内存页到磁盘在一个长期运行的进程可能会导致所有可用的物理内存的计算机上有效地消失,直到机器重新启动。 我们必须加载到本机的过程,将使用EmptyWorkingSet API(使用SetProcessWorkingSetSize替代),以减少执行内存密集型任务后,工作集一个.NET的DLL。 我发现有1天之间的任何地方,以一个星期后,机器会显示在任务管理器中99%的物理内存的使用,同时被证明没有进程将使用任何显著的内存使用情况。 不久后机器会变得反应迟钝,需要硬重启。 说机器均超过2打的Windows Server 2008 R2和在物理和虚拟硬件上运行2012 R2的服务器。
也许有加载到本机进程的.NET代码有一些东西需要做,但需要您自担风险使用EmptyWorkingSet(或SetProcessWorkingSetSize)。 也许只有初始启动应用程序后,使用一次。 我已决定禁止的代码,让垃圾收集管理自身的内存使用情况。