简体   繁体   English

c#:模拟内存泄漏

[英]c# : simulate memory leaks

I would like to write the following code in c#. 我想在c#中编写以下代码。 a) small console application that simulates memory leak. a)模拟内存泄漏的小型控制台应用程序。 b) small console application that would invoke the above application and release it right away simulating managing memory leak problem.. b)小型控制台应用程序,它将调用上述应用程序并立即释放它,模拟管理内存泄漏问题。

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). 换句话说,(b)应用程序将连续调用和释放应用程序(a)以模拟“反叛”内存泄漏应用程序如何被包含而不解决应用程序(a)的根本原因。

Some sample code for application (a) and (b) would be very helpful. 应用程序(a)和(b)的一些示例代码将非常有用。

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. 看一下Process类的属性 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! 只需创建IDisposable对象,不要丢弃它们! Examples being Image Graphics or any kind of handle or code that branches out into unmanaged code to create/manage resources. 示例是Image Graphics或任何类型的句柄或代码,它们分支到非托管代码中以创建/管理资源。

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. 以下内容解决了您想要的问题(a)从控制台应用程序中逐渐记忆泄漏,您可以在其中设置泄漏量和泄漏时间。

  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) 参数#1是它将以兆字节消耗的内存(即6000是6 Gigs)
  3. Parameter #2 is the Gradual Delay for each Iteration (ie 1000 is 1 second) 参数#2是每次迭代的渐变延迟(即1000是1秒)
  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. 它被设计为使用XmlNode作为占用内存的对象,因为COMMITTED MEMORY(由OS中的进程分配的内存)和WORKING SET MEMORY(进程实际使用的内存)将是相同的。 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. 如果使用原始类型来占用诸如byte []数组之类的内存,则WORKING SET通常什么都不是,因为即使已经分配了内存,该进程实际上也不会使用该内存。

Make sure to compile in x64 under the Project Properties under the Build Tab. 确保在Build选项卡下的Project Properties下的x64中编译。 Otherwise if its compiled in x32 then it will get an OutOfMemory error around the 1.7Gigs limit. 否则,如果它在x32中编译,那么它将在1.7Gigs限制附近获得OutOfMemory错误。 In x64 the Memory it eats up will be pretty "limitless". 在x64中,它吃掉的内存将非常“无限”。

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). 正如Brian Gideon的答案已经建议的那样,您可以使用以下代码调用此函数,然后将您的部分(b)删除。 The example below calls MemoryHog.exe (the program from the code above) to eat up 6 Gigs and pausing every 2 seconds 下面的示例调用MemoryHog.exe(上面代码中的程序)占用6 Gigs并且每2秒暂停一次

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 . 在控制台或Win应用程序中创建一个Panel对象(panel1),然后添加1000 PictureBox并设置其Image属性,然后调用panel1.Controls.Clear All PictureBox controls are still in the memory and no way GC can collect them: 所有PictureBox控件仍然在内存中, GC无法收集它们:

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() 调用Controls.Clear()时内存泄漏

Calling the Clear method does not remove control handles from memory. 调用Clear方法不会从内存中删除控制句柄。 You must explicitly call the Dispose method to avoid memory leaks 您必须显式调用Dispose方法以避免内存泄漏

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

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. 此代码使应用程序消耗越来越多的内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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