【问题标题】:Best practices to optimize memory in C# [closed]在 C# 中优化内存的最佳实践 [关闭]
【发布时间】:2014-01-29 13:11:34
【问题描述】:

在 C# 中优化内存的最佳实践是什么。

我正在使用以下技术来优化我的记忆力。

  1. 使用后处置对象或使其为空。
  2. 使用 try/finally 或使用块。
  3. 如果需要,使用 GC.Collect()。
  4. 删除不必要的对象初始化。
  5. 管理图像缓存。
  6. 管理 BLOB 数据、内存流和文件流

即使有内存泄漏。

我的应用程序正在使用以下内容:

  1. 处理配置文件,
  2. 使用其他 XML 文件。
  3. 使用图像功能放大、缩小、显示不同类型的图像、更改图像颜色、以 xml 格式保存数据。
  4. 在 SQL Server 中保存数据。

【问题讨论】:

  • 我不知道你在说什么。
  • 除了using 块之外,您为什么认为您必须这样做? C# 通常不会出现内存泄漏。
  • 非常种情况,你应该手动调用GC.Collect
  • 没有一种方法可以“优化”内存,我认为您需要描述您的问题,以便首先对其进行诊断。 “即使有内存泄漏”是什么意思?如果您(还)没有问题,那么您应该等待“优化”,直到您遇到具体问题。同时,只需遵循最佳实践,例如正确使用 Dispose。
  • 我无法追踪内存泄漏的位置。

标签: c# memory-leaks


【解决方案1】:

您可以使用 Redgate ANTS 内存分析器(非免费)。

CLR 分析器(免费):https://msdn.microsoft.com/library/ms979205

GC.Collect() 不推荐,即使在某些情况下需要。请看下面的代码:

private void WriteStringOnImage()
{
    try
    {
        byte[] imgData = getData(@"E:\0000.tif");
        using (System.Drawing.Image img = System.Drawing.Image.FromStream(new MemoryStream(imgData)))
        {
            for (int i = 1; i <= 1000; i++)
            {
                Bitmap img1 = new Bitmap(new Bitmap(img));
                RectangleF rectf = new RectangleF(800, 550, 200, 200);
                Graphics g = Graphics.FromImage(img1);
                g.DrawString(i.ToString("0000"), new Font("Thaoma", 30), Brushes.Black, rectf);
                img1.Save(@"E:\Img\" + i.ToString("0000") + ".tif");
                g.Flush();
                g.Dispose();
                img1.Dispose();
                GC.Collect();
            }
        }
    }
    catch (Exception){}
}

在上面的示例中,我使用了GC.Collect(),因为如果我不使用GC.Collect(),那么它会占用大约1500mb 的内存。但是在使用GC.Collect() 之后,如果永远不会超过 75mb

即内存利用率减少了 20 倍

但是如果GC.Collect() 被过度使用并且内存中没有太多未使用的对象,那么GC.Collect() 会降低你的性能并且很耗时。

如果它实现了IDisposable,你也可以使用Dispose()

如果您正在使用MemoryStream 或任何其他类型的流,那么您应该使用using 块。

有时您还需要清空一些对象,将其设为null

我们知道数据,如果我们处理 XML 数据,那么它会占用非常大的内存,所以我们需要在使用后释放内存,但是 XML 类没有实现 Idisposable 接口,所以你必须让它为空(例如xmldocument=null;

您还应该记住不必要的对象初始化

例如而不是:

ClassA abc=new ClassA();
abc=xyz;

用途:

ClassA abc=xyz;

如果仅在一种方法中使用,请尝试使用方法级别变量而不是类级别。

确保您正在清除集合对象。

密切关注您的应用程序中使用的任何第三方工具的内存使用情况。有时第三方工具会占用非常高的内存。

只有在必要时才使用static

使用StringBuilder而不是String因为如果将字符串连接起来,则会分配新内存,因此旧内存数据不会被使用,而是保存在RAM中。

如果在分层类中处理任何大型对象,请密切注意它。

如果任何 XML 文档已被处理并保存在内存中以供将来使用,并且将在任何事件之后使用,则释放该内存并在触发所需事件时加载 XML。

避免克隆。

如果您正在处理字符串操作,您可以检查数据是否存在无限循环。有时,省略号(...)等特殊 Unicode 字符会产生问题并导致无限循环。

您还可以使用 dotTrace Jetbrain 的内存分析器。

您还可以查看事件日志,了解导致问题的任何异常。

如果正在创建任何位图对象并且正在处理一些图像,那么请查看非托管资源。 位图对象为非托管资源占用大量内存并且可能不会被释放。

正如您所提到的,您也在使用 SQL 服务器,那么还要注意 SQL 服务器过程和函数 及其调用策略。

在 SQL Server 中,如果您将任何数据保存为图像数据类型并且大于 1mb,请使用 varbinary(MAX) 和 filestream 属性,但它适用于 SQL Server 2008 或更高版本SQL Server 的版本。

【讨论】:

  • 不要多次显式调用 GC.Collect()。这将非常耗时。
  • 我使用过 Redgate 内存分析器,但它对我帮助不大。我怎么能看到哪个类的内存泄漏了,或者内存中还有什么不必要的对象? Redgate 分析器显示 55% (400mb) 内存用于非托管代码。但我无法看到哪些非托管代码占用了内存。
  • 您有最新版本的 RG 分析器吗? v8 - 最近发布 - 让您可以在那个非托管块中四处寻找。
【解决方案2】:

..or make it null 的效果与Dispose() 不一样! 当心。您只应该处置您的对象。不需要设置为null 并且设置为null 不会立即释放任何资源。

  1. 如果需要,使用 GC.Collect()。

通常这不是必需的,因为 GC 有自己的生命周期来收集。从 .NET 4.5 开始,如果您认为存在碎片,您可以压缩 LOH:

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();    

【讨论】:

  • 但我使用的是框架 4.0 而不是 4.5。
【解决方案3】:

在 C# 中优化内存的最佳实践,

  1. 仅在需要时创建对象
  2. 确定每个变量和对象的范围,如果在方法中需要它们,在这些方法中声明它们,不要让它们private
  3. 在您的自定义对象上使用IDisposable 接口并释放所有资源(如果有),从所有事件中取消注册等
  4. 当您的自定义对象不再需要某个对象时,请调用 dispose
  5. 至少使用 static 变量或实例,如果需要,那么也要三思而后行,在程序的整个生命周期中是否需要这些对象
  6. 不要手动使用GC.Collect(),(这是不好的做法)

【讨论】:

    【解决方案4】:

    其中许多并没有真正优化内存...

    1. 在使用后处置对象或将其设为 null。 如果对象为 IDisposable,则始终为 Dispose()。这可以为您节省内存问题,但不一定。 (另外,如果可能,请使用Using
    2. 使用 try/finally 或使用块。 try/finally - 这类似于 Using 用于不是 IDisposable 的对象(我发现它们很乱,所以我更喜欢 this 解决方案.)
    3. 如果需要,请使用 GC.Collect()。 我真的无法推荐 GC.Collect()。通常GC 在知道何时收集东西方面会比你做得更好。
    4. 删除不必要的对象初始化。这个肯定有帮助。如果您的代码正在创建不需要的对象......那么这可能会浪费一些空间。这可以通过Lazy Initialization 来缓解/屏蔽。
    5. 管理图像缓存。这是非常模糊的......但是是的......管理您在内存中存储的图像数量很重要。将图像保存在内存中可能并不总是可取的......它可以为代码中更关键的其他进程打开分页的大门。
    6. 管理 BLOB 数据、内存流和文件流 我觉得这和 #5 差不多。

    【讨论】:

    • 如果一个类没有实现 IDisposable 接口,那么释放内存的最佳方法是什么?
    • 这取决于您何时说“空闲内存”。 GC 将处理任何数组以及您没有的数组。但是,如果您打开了类似FileStream 的东西,则需要调用其Dispose() 方法。如果你创建了一个类,它的成员实现了IDisposable,那么你应该让你的类实现IDisposable
    猜你喜欢
    • 2011-01-22
    • 1970-01-01
    • 2017-11-10
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    相关资源
    最近更新 更多