【问题标题】:How to stop memory leaks in C# and what exactly are they? [duplicate]如何阻止 C# 中的内存泄漏,它们到底是什么? [复制]
【发布时间】:2019-09-20 02:09:37
【问题描述】:

3 个整体问题

通过注释掉某些行的试验和错误,某人有可能确定导致内存泄漏的行和/或函数。我已经这样做了,但是,使用 Visual Studio,我无法弄清楚如何查看每个变量占用了多少内存来找出导致内存泄漏的原因。这是我的第一个问题。

我的第二个是它们到底是什么,我过去读过很多关于引用停止 GC 的变量等的帖子,但我真的需要有人解释得更简单一些,因为这没有任何意义我。我相信许多其他人也有同样的感受。

最后,你如何阻止它们,我看过很多关于“取消订阅”事件等的文章,但它们似乎都不适用于我,所以这些技术都不能解决这个内存泄漏问题。我想知道一种更完整的方法来防止它们,如果我知道它们实际上是什么,我相信很容易理解。

个人问题

这是“我的代码不起作用”的问题之一。但是等等......不要生气。我的代码有内存泄漏,但是,根据我对它们的知识非常有限,我不明白这是怎么可能的。具有内存泄漏的函数没有任何行,我将值添加到变量(使其具有更大的大小),并且没有局部变量(这将是在函数末尾收集的垃圾,但可能不是并可能导致内存泄漏)。我的内存泄漏非常严重,每分钟会增加大约 1 GB 的内存使用量。顺便说一句,知道我在代码中使用 WPF 可能很有用,您可能会识别出文件名模式:NormalUI.xamlNormalUI.xaml.csProgram.cs

我没有附上我的完整代码,这是因为没有必要,我并不懒惰。我确保在保持错误存在的同时尽可能简化了我的代码(删除了一些东西)。 这也是为了让遇到相同问题的任何人都可以轻松查看此答案并修复自己的代码。

这是一个非常可怕的内存泄漏的图像:

简化代码 - NormalUI.xaml

  <Image x:Name="Map"/>

简化代码 - NormalUI.xaml.cs

    public NormalUI() 
    {
        // Setup some variables


        // Start the timer to continually update the UI
        System.Timers.Timer EverythingUpdaterTimer = new System.Timers.Timer(); 
        EverythingUpdaterTimer.Elapsed += new ElapsedEventHandler(UpdateEverything);
        EverythingUpdaterTimer.Interval = 100; // this has a memory leak
        EverythingUpdaterTimer.Enabled = true;
        InitializeComponent();

    }

    public void UpdateEverything(object source, ElapsedEventArgs e) // THIS FUNCTION CALLS THE FUNCTION WITH THE MEMORY LEAK (I THINK(
    {


        try // Statistics and map (won't work at the start before they have been declared... since this is a timer)
        {
        Dispatcher.Invoke(() => // Because this is a separate "thread"... I think...
        {
            // Update the map (height and width in the case of a load)
            Map.Height = MAP_HEIGHT;
            Map.Width = MAP_WIDTH;
            Map.Source = Program.CalculateMap();

        });


        }
        catch
        {
            Program.Log("Couldn't update general UI information"); 
        }


    }

简化代码 - Program.cs

        public static ImageSource CalculateMap()
        {
            /* This function is responsible for creating the map. The map is actually one large
             * picture, but this function gets each individual smaller image (icon) and essentially
             * "squashes" the images together to make the larger map. This function is used every
             * single turn to update what the map looks like.
             */

            List<List<Image>> map = new List<List<Image>>(world.rows);

                // Create the empty world
                for (int r = 0; r < world.rows; r++)
                {
                    map.Add(new List<Image>(world.cols));  // Add images to list
                    for (int c = 0; c < world.cols; c++)
                    {
                        map[r].Add(EMPTY_ICON); // Add images to list
                    }

                }

            // Create the bitmap and convert it into a form which can be edited
            Bitmap bitmapMap = new Bitmap(world.rows * ICON_WIDTH, world.cols * ICON_HEIGHT); // Get it? bitmapMap... bitMap...
            Graphics g = Graphics.FromImage(bitmapMap);
            // Add images to the bitmap
            for (int r = 0; r < world.rows; r++)
            {
                for (int c = 0; c < world.cols; c++)
                {
                    g.DrawImage(map[r][c], (c) * ICON_WIDTH, (r) * ICON_HEIGHT, ICON_WIDTH, ICON_HEIGHT);
                }
            }
            // Convert it to a form usable by WPF (ImageSource).

            ImageSource imageSourceMap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                bitmapMap.GetHbitmap(),
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());
            // Return the new ImageSource.
            return imageSourceMap;

        }

非常感谢您回答我的个人问题......以及整个问题。

【问题讨论】:

  • 一般情况下,您不会在 WPF 应用程序中使用 WinForms 绘制 Bitmap 和 Graphics 之类的东西。如果这样做,请注意删除从 GetHbitmap 返回的句柄。
  • 每 100 毫秒执行一次看起来相当昂贵的图像处理是一个坏主意。构建图像的整个方式看起来很奇怪。通常我只会说获得试用蚂蚁内存分析器,但我认为你可能在那里遇到基本的设计问题。

标签: c# wpf visual-studio memory-leaks out-of-memory


【解决方案1】:

唯一需要处理的对象是非 .NET 对象。如果底层 O/S 需要诸如 CloseHandle(或类似)之类的东西来释放内存,那么您将需要在 .NET 代码中处理该对象。

如果任何 .NET 类实现 IDisposable,您必须调用 .Dispose()

您可以使用 VS 中内置的代码分析器等工具来指出对象在何处具有 Dispose,但您并没有调用它。

【讨论】:

    猜你喜欢
    • 2016-01-01
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 2019-09-21
    • 2017-12-13
    • 1970-01-01
    相关资源
    最近更新 更多