1

3 Overall Questions

Through trial and error of commenting out certain lines it is possible for someone to determine the line and/or function which is causing a memory leak. I have done this, however, using Visual Studio, I cannot figure out how to view how much memory each variable is taking up to find out which is causing a memory leak. That is my first question.

My second is what exactly are they, I have read many posts in the past about references to variables stopping the GC and so on, but I really need someone to explain a bit simpler, because that just doesn't make sense to me. And I am sure many others feel the same way.

Lastly, how do you stop them, I have seen many articles on "unsubscribing" to events and such, but none of them seem to apply to me so none of those techniques work to solve this memory leak. I want to know a more complete way of preventing them which I am sure can be easily understood if I knew what they actually are.

Personal Question

This is one of those "my code is not working" questions. But wait... don't rage yet. My code has a memory leak however, from my very limited knowledge of what they are, I do not understand how this is possible. The function with the memory leak does not have any lines where I add values to a variable (to make it have a larger size), and there are no local variables (which would be Garbage Collected at the end of the function but may not be and might cause memory leaks). My memory leak is very severe, it adds approximately a Gigabyte a minute of memory being used. By the way, it might be useful to know that I am using a WPF in my code, you may recognise the file name patterns: NormalUI.xaml, NormalUI.xaml.cs, Program.cs.

I did not attach my full code, this is because there is no need and I am not lazy. I have made sure that I simplified my code (removed stuff) as much as I could while keeping the error present. This is also so that anybody experiencing the same problem can easily look at this answer and fix their own code.

Here is an image of the quite scary memory leak:

Memory Leak

Simplified Code - NormalUI.xaml

  <Image x:Name="Map"/>

Simplified Code - 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"); 
        }


    }

Simplified Code - 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;

        }

I would very much appreciate an answer to my personal question... as well as the overall question.

Elodin
  • 650
  • 5
  • 23
  • 1
    In general, you won't use WinForms drawing stuff like Bitmap and Graphics in a WPF application. If you do, take care to delete handles like the one returned from GetHbitmap. – Clemens May 01 '19 at 14:41
  • Doing what looks like quite expensive image manipulation every 100 milliseconds is a bad idea. That whole way of building your image looks odd. Usually i'd just say get the trial ants memory profiler but i think you might have fundamental design issues there. – Andy May 01 '19 at 17:49

1 Answers1

-1

The only objects that requires disposing are non-.NET objects. If the underlying O/S requires something like CloseHandle (or similar) to free up memory, then you will need to dispose that object in .NET code.

If any .NET classes implement IDisposable you MUST call .Dispose().

You can use tools such as the code analyser built into VS to point out where objects have a Dispose, but you aren't calling it.

Neil
  • 11,059
  • 3
  • 31
  • 56