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

时间:2014-01-10 14:09:40

标签: c# memory-leaks

在C#中优化内存的最佳做法是什么?

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

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

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

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

4 个答案:

答案 0 :(得分:10)

您可以使用 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()会降低您的性能并且耗时。

如果Dispose()实施IDisposable,您也可以使用MemoryStream

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

有时您还需要通过将某个对象设为xmldocument=null; 来清空它。

如果我们知道数据,如果我们处理XML数据然后它需要非常大的内存,所以我们需要在使用后释放内存但是XML类没有实现Idisposable接口所以你必须使它为null(例如ClassA abc=new ClassA(); abc=xyz;

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

e.g。而不是:

ClassA abc=xyz;

使用:

static

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

确保清除收集对象。

请关注应用程序中使用的任何第三方工具的内存使用情况。有时第三方工具会占用很高的内存。

仅在必须时才使用StringBuilder

使用String代替{{1}}。因为如果字符串连接在一起,则会分配一个新内存,因此旧内存数据不会被使用但会保留在RAM中

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

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

避免克隆。

如果您正在使用字符串操作,则可以检查数据是否为无限循环。有时像Unicode(...)这样的特殊Unicode字符会产生问题并导致无限循环。

你也可以使用Jetbrain的 dotTrace 内存分析器。

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

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

正如您所提到的,您也在使用SQL服务器,那么还要关注 SQL服务器程序和功能及其调用策略。

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

答案 1 :(得分:2)

在C#中优化内存的最佳做法,

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

答案 2 :(得分:2)

其中许多并没有真正优化记忆......

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

答案 3 :(得分:0)

..or make it nullDispose()的效果不同! 小心点。你应该只处理你的对象。不需要设置为null。 并设置为null不释放任何资源。

  

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

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

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