我注意到通常的高内存大小。我写的一个应用程序是一个控制台应用程序,它使用< 50lines并且只使用WebRequest简单地下载一系列文件。另一个不重要的应用程序(mysql,dls,多线程,包含100个项目的列表框)。第一个使用21 MB(debug,ide),另一个使用39mb(debug,ide)。我还有另一个应用程序轮询我的网站(也使用WebRequest)进行状态更新,该更新位于我的托盘上并使用26mbs通知我(发布,而不是通过ide)。
为什么这么高?我知道我上面写了一个C ++应用程序,使用curl运行< 2mb,我最大的C ++ prj是11mb,加载100kb dll和200kb二进制文件(使用带有win32图标和声音的directx)。我如何编译我的C#代码,使其更加空间友好。我想将这些部署到一个服务器上,这个服务器可能只有128或256mb ram,其中一些应用程序会杀死它。
网站注意:我在发布模式(通过ide)运行了第一个提到的应用程序(控制台DLer),它跳到了32mb。为什么!?!那更令人困惑。
答案 0 :(得分:5)
老实说,在您能够测量其内存大小产生问题的情况之前,不要担心托管代码的足迹。当您启动.NET程序集时,CLR会执行许多不同的操作,但在此处列出的内容太多,但请参阅http://weblogs.asp.net/pwilson/archive/2004/02/14/73033.aspx,有关更多资源,请参阅http://geekswithblogs.net/sdorman/archive/2008/09/14/.net-memory-management-ndash-resources.aspx
请查看本文,了解如何根据内存条款确定应用程序的实际用途,因为任务管理器不会显示真实的故事http://www.codinghorror.com/blog/archives/000271.html
如果你真的真的想在任务管理器中使用比你需要放弃托管代码更少的内存来展示你的程序集。欺骗的一种方法是使用Salamander Protector之类的东西来编译应用程序,这使得应用程序成为本机可执行文件而不是.NET程序集。
答案 1 :(得分:3)
由于多种原因,小型.NET应用程序在内存占用方面无法真正与C / C ++应用程序竞争。
与本机应用程序启动所需的内容相比,.NET运行时非常庞大。为了运行.NET应用程序,CLR必须在内存中。它不仅需要加载诸如JIT编译器,GC等组件,还需要许多内部数据结构。例如。即使是最简单的.NET应用程序也有三个AppDomain,其中两个由CLR内部使用,另一个用于应用程序本身。
此外,组件在被引用时被加载。即使这些方法在需要之前没有被jitted,组件本身在加载时会占用大量的地址空间。当代码在某个时刻被jitted时,它将作为本机代码再次存储在内存中。所以基本上编译的代码在.NET应用程序中出现两次。
最后,与在C / C ++应用程序中找到的类型相比,类型系统在.NET上更加精细。每个对象都携带有关其类型的信息。这允许反射和其他有用的功能,但它确实需要付出代价。
如果你想占用非常小的.NET可能已经足够好了,但它肯定不是最明显的选择,因为你将为运行时的开销付出代价。
此外,请参阅此相关问题Reducing memory usage of .NET applications?
答案 2 :(得分:2)
我不是CLR的专家,但我注意到CLR会以块的形式分配内存,并且即使你的应用程序没有使用那么多内存也可能会非常高。它有点像CLR喜欢保留它不需要的内存,因此它不需要调用windows来重新分配。
检查应用程序的私有字节。私有字节应该是您实际使用的内存的更合理的指示,而不是CLR持有多少。此外,设置进程的MaxWorkingSet似乎可以在任务管理器中神奇地重新校准统计信息。
System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
loProcess.MaxWorkingSet = loProcess.MaxWorkingSet;
上面的代码看起来像TheDailyWtf的候选人。 LOL
答案 3 :(得分:0)
要记住的一件事是垃圾收集器在其他需要它之前不会总是释放内存。因此,即使您的应用程序可能声称使用100MB内存,实际上它可能使用50MB,但垃圾收集器还没有理由收集并释放其余部分。
即使应用程序的基本初始化也会产生大量临时值,这会导致CLR为应用程序分配内存块。只要系统有足够的内存,垃圾收集就会检测和清理未使用的内存非常懒惰;这是速度优化。不要担心,当你的系统开始需要更多内存时,垃圾收集会启动并开始进行更深入的扫描。
确保您没有手动调用垃圾收集器,调用的次数越多,将更多的对象推送到更高代,直到系统内存不足才会收集这些对象。