3

我注意到通常的高内存大小。我编写的一个应用程序是一个控制台应用程序,它使用 <50lines 并且仅使用 WebRequest 简单地下载一系列文件。另一个不重要的应用程序(mysql、dls、多线程、包含 100 个项目的列表框)。第一个使用 21 mb (debug, ide),另一个使用 39mb(debug, ide)。我还有另一个应用程序轮询我的网站(也使用 WebRequest)以获取位于我的托盘上的状态更新,并使用 26mbs(发布,未通过 ide)通知我。

为什么这些这么高?我知道我使用 curl 编写了一个类似上面的 C++ 应用程序,它运行 <2mb,我最大的 C++ prj 是 11mb,它加载一个 100kb dll 和一个 200kb 二进制文件(使用带有 win32 图标和声音的 directx)。我怎样才能编译我的 C# 代码,使其更加空间友好。我想将这些部署到可能只有 128 或 256mb 内存的服务器上,其中一些应用程序会杀死它。

站点注释:我在发布模式下(并通过 ide)运行了提到的第一个应用程序(控制台 DLer),它跃升至 32mb。为什么!?!那更令人困惑。

4

4 回答 4

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 程序集。

于 2009-11-27T04:09:22.617 回答
3

由于多种原因,小型 .NET 应用程序在内存占用方面无法真正与 C/C++ 应用程序竞争。

与本机应用程序启动所需的相比,.NET 运行时是巨大的。为了运行 .NET 应用程序,CLR 必须在内存中。它不仅需要加载 JIT 编译器、GC 等组件,还需要一些内部数据结构。例如,即使是最简单的 .NET 应用程序也有三个 AppDomain,两个由 CLR 内部使用,一个用于应用程序本身。

此外,程序集在被引用时会被加载。即使这些方法在需要时不会被 jit,但程序集本身在加载时会使用大量地址空间。当代码在某个时刻被 jit 处理时,它会作为本机代码再次存储在内存中。所以基本上编译的代码在 .NET 应用程序中出现了两次。

最后,与您在 C/C++ 应用程序中发现的相比,.NET 上的类型系统要复杂得多。每个对象都携带有关其类型的信息。这允许反射和其他有用的功能,但它确实是有代价的。

如果您想要非常小的占用空间,.NET 可能就足够了,但它肯定不是最明显的选择,因为您将支付运行时的开销。

另外,请参阅此相关问题Reducing memory usage of .NET applications?

于 2009-11-27T05:37:24.433 回答
2

我不是 CLR 方面的专家,但我注意到 CLR 会以块的形式分配内存,并且即使您的应用程序不使用那么多内存,它也会膨胀得非常高。它有点像 CLR 喜欢保留它不需要的内存,因此它不需要调用窗口来重新分配。

检查应用程序的私有字节。私有字节应该是您实际使用的内存的更合理指标,而不是 CLR 保留了多少。此外,设置进程的 MaxWorkingSet 似乎可以神奇地重新校准任务管理器中的统计信息。

System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
loProcess.MaxWorkingSet = loProcess.MaxWorkingSet;

上面的代码看起来像是 TheDailyWtf 的候选代码。哈哈

于 2009-11-27T04:14:07.690 回答
0

要记住的一件事是垃圾收集器不会总是释放内存,直到其他东西需要它。因此,即使您的应用程序可能声称使用了 100MB 的内存,但实际上它可能使用了 50MB,但垃圾收集器还没有理由收集并释放其余的内存。

即使是应用程序的基本初始化也会创建大量临时对象,这会导致 CLR 为应用程序分配内存块。只要系统有足够的内存,垃圾收集就会非常懒惰地检测和清理未使用的内存;这是速度优化。不要担心,当您的系统开始需要更多内存时,垃圾收集将启动并开始进行更深入的扫描。

确保您没有手动调用垃圾收集器,它被调用的次数越多,就会有越多的对象被推入更高代,直到系统内存不足时才会被收集。

于 2009-11-27T04:22:03.870 回答