【问题标题】:Do I have a serious memory leak problem?我有严重的内存泄漏问题吗?
【发布时间】:2011-05-18 16:18:50
【问题描述】:

我正在用 C# 构建一个 Windows 窗体应用程序,它从数百个文件中读取并创建一个对象层次结构。特别是:

DEBUG[14]: Imported 129 system/s, 6450 query/s, 6284293 document/s.

总和是我创建的对象的总数。顺便说一句,对象真的很简单,里面只有一些 int/string 属性和强类型列表。

问题:我的应用程序消耗大约 700MB 内存(在调试模式下)是否正常?如何减少内存使用量?

编辑:这就是为什么我有 6284293 个对象,如果你只是好奇的话。想象一个搜索引擎,称为“系统”。系统内部有更多查询。

public class System
{
  public List<Query> Queries;
}

每个查询对象都引用一个“主题”;这是主要论点(例如,搜索“意大利周末”)。它里面有一个检索到的文档列表:

public class Query
{
  public Topic Topic; // Maintain only a reference to the topic
  public List<RetrievedDocument> RetrievedDocuments;
  public System System; // Maintain only a reference to the system
}

每个检索到的文档都有一个分数和一个排名,并且有一个对主题文档的引用:

public class RetrievedDocument
{
  public string Id;
  public int Rank;
  public double Score;
  public Document Document;
}

每个主题内部都有一个文档集合,可以相关或不相关,以及对其父主题的引用:

public class Topic
{
  public int Id;
  public List<Document> Documents;
  public List<Document> RelevantDocuments
  {
    get {return Documents.Where(d => d.IsRelevant());}
  }
}

public class Document
{
  public string Id;
  public bool IsRelevant;
  public Topic Topic; // Maintain only a reference to the topic
}

有 129 个系统,50 个主要主题(129*50 = 6450 个查询对象),每个查询有不同数量的检索到的文档,总共 6284293 个。我需要这个层次结构来进行一些计算(平均精度、主题易用性、系统平均平均精度、相关性)。这就是 TREC 的工作原理...

【问题讨论】:

  • 这听起来相当合理,大小明智。
  • 6284293 documents 是否意味着您有 6284293 个对象?
  • @Gabe: 是的,这个数字是所有导入文件的总行数(约 130 个 txt 文件),并且为每一行创建一个“文档”类型的对象...
  • 所以大约 7M 个对象,每个大约 100 字节,给你大约 700MB。那你有什么问题?
  • @Gabe:我问这个是因为我不是大师。

标签: c# performance forms memory-leaks memory-management


【解决方案1】:

去获取scitech profiler(两周免费试用)并找出答案。

注意空列表,它们每个占用 40 个字节。

【讨论】:

    【解决方案2】:

    如果不了解您的代码,很难说出发生了什么,但这里有一些想法和建议:

    • 确保在读完文件后关闭它们

    • 确保您没有维护对不存在的对象的引用 使用时间更长

    • 查看您使用的数据结构。有时候,还有更多 节省内存的方式来安排你的 数据

    • 查看您的数据类型,您在哪些地方使用 Long 或 Double 字节就够了?

    • 每个程序在调试模式下都会比非调试模式使用更多的内存, 但区别应该在 单个或 10 兆字节的顺序, 不是数百。可以用任务吗 经理检查多少内存 您在调试模式之外使用?

    【讨论】:

    • 看来,对于我的问题,使用对象建模是最好的方法。无论如何,在发布模式下,导入文件时仍然消耗大约 700MB。
    • 同意所有这些,但是,如果他相当快地创建这些对象,可能是 GC 无法跟上释放和合并内存的速度,即使他正在释放和关闭他所有的资源。我认为底线是,如果您要读取数百个文件,每个文件都有完整的对象层次结构,那么您将消耗大量内存。
    【解决方案3】:

    如果您正在阅读 6284293 个文档并在对象层次结构中保留这些文档,那么显然您的应用程序会使用大量内存。鉴于我们不知道这些对象的大小,很难说您使用的是否超出预期。

    另外,请记住 CLR 代表您的应用程序分配和释放内存。因此,即使您的应用程序已释放内存,这也可能不会立即反映在进程的内存使用情况上。如果应用程序没有泄漏,此内存将在某个时候被回收,但您不应期望看到托管内存使用情况会立即反映在进程内存使用情况中,因为 CLR 可能会保留内存以减少分配/释放的次数。

    【讨论】:

    • 对,直到 GC 运行,内存使用才会真正下降,对吗?我在实践中发现,如果有足够的 RAM 可用并且您的应用程序正在快速生成对象(即没有很多空闲时间),这可能需要相当长的时间。理论上我认为只要你有可用的 RAM,你就不需要 GC(尽管实际上当 GC 收集/整合速度不够快时我遇到了内存碎片问题)
    • @James B:GC 将回收托管内存。但是,CLR 可能会保留为除此之外的进程分配的内存。作为优化,CLR 以块的形式与操作系统一起分配和释放内存。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 1970-01-01
    • 2016-07-28
    相关资源
    最近更新 更多