【问题标题】:c# : simulate memory leaksc# : 模拟内存泄漏
【发布时间】:2010-06-10 23:23:02
【问题描述】:

我想用 c# 编写以下代码。 a) 模拟内存泄漏的小型控制台应用程序。 b) 小型控制台应用程序,它将调用上述应用程序并立即释放它,以模拟管理内存泄漏问题..

换句话说,(b) 应用程序将不断调用和释放应用程序 (a) 以模拟“叛逆”内存泄漏应用程序是如何被遏制的,而没有解决应用程序 (a) 的根本原因。

应用程序 (a) 和 (b) 的一些示例代码会很有帮助。

谢谢

【问题讨论】:

  • 这听起来像是我的功课。

标签: c# memory memory-leaks


【解决方案1】:

泄漏的应用程序可能如下所示:

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.
  }
}

调用应用程序可能如下所示:

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

看看properties on the Process 类。有几个返回进程消耗的内存量。您也许可以使用其中之一来有条件地终止该进程。

【讨论】:

  • 我实现了你的示例代码。我的 Leaker.exe 以每个任务管理器进程选项卡的 6MB 内存使用量开始。我不知道我可以用哪个属性来测量它......我从 NonpagedSystemMemorySize 一直到 VirtualMemorySize64 都得到了几个属性,但我不知道哪个属性对应于任务管理器的内存使用情况。我试图将内存属性值打印到控制台,但仍然没有运气。请帮忙。
  • 通过创建更大的byte 数组让泄漏者更积极地消耗内存。尝试使用PrivateMemorySize64。随着时间的推移,它应该会开始蔓延。
【解决方案2】:

只需创建 IDisposable 对象,不要丢弃它们!示例为 Image Graphics 或任何类型的句柄或分支到非托管代码以创建/管理资源的代码。

【讨论】:

  • IDisposable 在这里没有做任何特别的事情。任何对象都可以工作,只要您不让它变得无法访问。
【解决方案3】:

在控制台或 Win 应用程序中创建一个 Panel 对象(panel1),然后添加 1000 个 PictureBox 并设置其 Image 属性,然后调用 panel1.Controls.Clear。所有 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!

正确的做法是

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

Memory leaks in calling Controls.Clear()

调用 Clear 方法不会从内存中删除控制句柄。 您必须显式调用 Dispose 方法以避免内存泄漏

【讨论】:

  • 这应该是正确的答案。现实世界,可能的错误。
【解决方案4】:

以下解决了您在 (a) 控制台应用程序的逐渐内存泄漏中想要的内容,您可以在其中设置泄漏量和泄漏持续时间。

  1. 逐渐消耗内存的控制台应用
  2. 参数 #1 是它将消耗的内存,以 MB 为单位(即 6000 是 6 Gigs)
  3. 参数 #2 是每次迭代的渐进延迟(即 1000 是 1 秒)
  4. 承诺的内存和工作集将大致相同

它被设计为使用 XmlNode 作为占用内存的对象,因为这样 COMMITTED MEMORY(操作系统中进程分配的内存)和 WORKING SET MEMORY(进程实际使用的内存)将是相同的。如果使用原始类型来占用内存,例如 byte[] 数组,那么 WORKING SET 通常什么都不是,因为即使分配了内存,进程实际上也没有使用。

确保在 Build 选项卡下的 Project Properties 下以 x64 编译。否则,如果它在 x32 中编译,那么它将在 1.7Gigs 限制附近出现 OutOfMemory 错误。在 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();
            
        }

    }
}

正如 Brian Gideon 的回答已经推荐的那样,您可以使用以下代码调用它,然后终止您的部分 (b) 进程。下面的示例调用 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();

        }
    }
}

【讨论】:

    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      我用这段代码创建了我的:

      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
              }
          }
      
      }
      

      【讨论】:

        【解决方案7】:

        我已尝试使用已接受的答案中描述的方法,但它不起作用 - 编译器或运行时似乎已将其优化掉。

        我找到了最简单的修改方法:

        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);
        }
        

        这段代码使应用程序消耗越来越多的内存。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-12-27
          • 2016-01-27
          • 2010-11-11
          • 2017-02-18
          • 1970-01-01
          • 2015-11-19
          • 2014-11-01
          相关资源
          最近更新 更多