简体   繁体   中英

c# : simulate memory leaks

I would like to write the following code in c#. a) small console application that simulates memory leak. b) small console application that would invoke the above application and release it right away simulating managing memory leak problem..

In other words the (b) application would continuously call and release application (a) to simulate how the "rebellious" memory leak application is being contained with out addressing the root cause which is application (a).

Some sample code for application (a) and (b) would be very helpful.

Thanks

The leaking application might look like:

public static void Main()
{
  var list = new List<byte[]>();
  while (true)
  {
    list.Add(new byte[1024]); // Change the size here.
    Thread.Sleep(100); // Change the wait time here.
  }
}

And the calling application might look like:

public static void Main()
{
  Process process = Process.Start("leaker.exe");
  process.Kill();
}

Take a look at the properties on the Process class. There are several that return how much memory the process is consuming. You may be able to use one of them to conditionally kill the process.

Just Create IDisposable objects and don't dispose them! Examples being Image Graphics or any kind of handle or code that branches out into unmanaged code to create/manage resources.

The below addresses what you want in (a) a Gradual Memory Leak from a Console App where you can set the amount to leak and the duration to leak it.

  1. Console App That Gradually Eats Up Memory
  2. Parameter #1 is the Memory it will Eat Up in Megabytes (ie 6000 is 6 Gigs)
  3. Parameter #2 is the Gradual Delay for each Iteration (ie 1000 is 1 second)
  4. The Committed Memory and Working Set will be around the Same

It was designed to use XmlNode as the object that takes up Memory because then the COMMITTED MEMORY (memory allocated by process in OS) and WORKING SET MEMORY (memory actually used by the process) would be the same. If a primative type is used to take up memory such as a byte[] array, then the WORKING SET usually is nothing, because the memory is not actually be used by the process even though its been allocated.

Make sure to compile in x64 under the Project Properties under the Build Tab. Otherwise if its compiled in x32 then it will get an OutOfMemory error around the 1.7Gigs limit. In x64 the Memory it eats up will be pretty "limitless".

using System;
using System.Xml;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace MemoryHog
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("    Total Memory To Eat Up in Megs: " + args[0]);
            Console.WriteLine("Millisecs Pause Between Increments: " + args[1]);            
            int memoryTotalInMegaBytes     = Convert.ToInt32(args[0]);
            int secondsToPause             = Convert.ToInt32(args[1]);

            Console.WriteLine("Memory Usage:" +     Convert.ToString(GC.GetTotalMemory(false)));

            long runningTotal = GC.GetTotalMemory(false);
            long endingMemoryLimit = Convert.ToInt64(memoryTotalInMegaBytes) * 1000 *     1000;
            List<XmlNode> memList = new List<XmlNode>();
            while (runningTotal <= endingMemoryLimit)
            {
                XmlDocument doc = new XmlDocument();
                for (int i=0; i < 1000000; i++)
                {
                    XmlNode x = doc.CreateNode(XmlNodeType.Element, "hello", "");
                    memList.Add(x);
                }
                runningTotal = GC.GetTotalMemory(false);
                Console.WriteLine("Memory Usage:" +     Convert.ToString(GC.GetTotalMemory(false)));
                Thread.Sleep(secondsToPause);
            }
            Console.ReadLine();

        }

    }
}

And as Brian Gideon's Answer already recommended, you can call this by using the following code and then killing the process your part (b). The example below calls MemoryHog.exe (the program from the code above) to eat up 6 Gigs and pausing every 2 seconds

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;

namespace ProcessLauncher
{
    class Program
    {
        static void Main(string[] args)
        {
            Process process = Process.Start("MemoryHog.exe", "6000 2000");
            Console.Read();
            process.Kill();

        }
    }
}

In a Console or Win app create a Panel object(panel1) and then add 1000 PictureBox having its Image property set then call panel1.Controls.Clear . All PictureBox controls are still in the memory and no way GC can collect them:

var panel1 = new Panel();
var image = Image.FromFile("image/heavy.png");
for(var i = 0; i < 1000;++i){
  panel1.Controls.Add(new PictureBox(){Image = image});
}
panel1.Controls.Clear(); // => Memory Leak!

The correct way of doing it would be

for (int i = panel1.Controls.Count-1; i >= 0; --i)
   panel1.Controls[i].Dispose();

Memory leaks in calling Controls.Clear()

Calling the Clear method does not remove control handles from memory. You must explicitly call the Dispose method to avoid memory leaks

您可以通过简单地将对象添加到计时器上的全局列表来模拟内存泄漏。

I created mine with this code:

internal class Program
{
    private static void Main(string[] args)
    {
        try
        {
            var limit = 9400;
            while (true)
            {
                var thread = new Thread(() => IncreaseMemory(limit));
                thread.Start();
            }
        }
        catch (Exception)
        {
            // swallow exception
        }

    }

    private static void IncreaseMemory(long limity)
    {
        var limit = limity;

        var list = new List<byte[]>();
        try
        {
            while(true)
            {
                list.Add(new byte[limit]); // Change the size here.
                Thread.Sleep(1000); // Change the wait time here.
            }
        }

        catch (Exception ex)
        {
            // do nothing
        }
    }

}

I have tried to use the approach, described in the accepted answer, but it didn't work - it looks like compiler or runtime have optimized this away.

I have found the simplest modification which makes this work:

var rnd = new Random();
var list = new List<byte[]>();
while (true)
{
    byte[] b = new byte[1024];
    b[rnd.Next(0, b.Length)] = byte.MaxValue;
    list.Add(b);

    Thread.Sleep(10);
}

This code makes application consume more and more memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM