C# 代码造成内存泄漏。

问题描述 投票:0回答:2

我想编写一个简单的 C# 程序/控制台应用程序来创建缓慢且受控的内存泄漏。我希望该程序慢慢耗尽系统内存。我需要这个来测试我正在测试的其他东西。

建议我使用:

Marshal.AllocHGlobal(numbytes)

附有计时器。

这是我尝试实现的代码:

class Program
{
    static Timer timer = new Timer();

    static void Main(string[] args)
    {
        timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

        start_timer();
        Console.Read();
    }

    static void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        IntPtr hglobal = Marshal.AllocHGlobal(100);
        Marshal.FreeHGlobal(hglobal);

        Process proc = Process.GetCurrentProcess();
        Console.WriteLine(proc.PrivateMemorySize64);
    }

    private static void start_timer()
    {
        timer.Start();
    }
}

输出似乎表明内存仍在管理中并且垃圾收集正在执行其工作。有人可以帮我解决这个问题吗?我的目标是确实造成内存泄漏并耗尽系统资源。有人请建议我的代码有什么问题,或者其他更好的选择。

c# memory memory-leaks
2个回答
3
投票

对于泄漏,您需要实际泄漏内存。现在,您不会泄漏任何内容,因为您释放了它:

    IntPtr hglobal = Marshal.AllocHGlobal(100);
    // DO NOT DO THIS IF YOU WANT A LEAK: Marshal.FreeHGlobal(hglobal);

0
投票

我需要为 Azure 应用服务中运行的应用程序的故障模式测试用例创建受控内存泄漏。

这是 MVC 类中的一个下降。

using System;
using System.Collections.Generic;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using log4net;

namespace foo.FooApp.MVC.UI.Controllers
{
    [Route("memleak")]
    public class MemLeakController : Controller
    {
        /*
         * This code is a simple drop in solution that can be placed into a MVC controller application and will create a controlled memory leak.
         * It provides three endpoints
         * /InitMem - This is the initial page that provides a link to start the memory leak
         * /RunMem - This page takes two parameters and will create a controlled memory leak.
         * * Parameter 1: MemToAllocate, this is the amount of memory to consume per each iteration.
         * * Parameter 2: MemToConsume, This is the number of allocation iterations.
         * /ClearMem - This will reset (clear) any memory allocations.
         * It was determined using a List of Bytes for memory allocation was a better solution than some of the other techniques, for example: Marshal.AllocHGlobal and static event EventHandler.
         * For measuring memory allocation it was determined that using GC.GetTotalMemory rather proc.PrivateMemorySize64 provided more accurate results.
         * This test will eventually cause an System.OutOfMemoryException. The Test can be reset by clicking on the clear memory link
         * As of now App Services will fail with out of memory after about 3.4 GB of memory allocation.
         */
        private static readonly ILog Logger =
            LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType);

        private const string MemClearHtml = "<ul><li><a href=\"/memleak/ClearMem\")\">"
                                            + "<span>Reset Memory Leak Test</span>"
                                            + "</a></li></ul>";

        private const string MemRunHtml = "<ul><li><a href=\"/memleak/RunMem?MemToConsume=5&MemToAllocate=100\")\">"
                                          + "<span>Run Memory Leak Test</span>"
                                          + "</a></li></ul>";

        private const string TextareaHeader = "<textarea id=\"foo\" rows=\"8\" cols=\"50\">";
        private const string TextareaFooter = "</textarea>";
        private static long _memToAllocate = 1000000 * 100; // 100 MB
        private static int _memToConsume = 5; // * _memToAllocate = 500 MB
        private static long _lastMem;

        // ReSharper disable once CollectionNeverQueried.Local
        private static readonly List<byte[]> ListToConsume = new List<byte[]>();

        /*
         * Initial page to start the memory leak test
         * Endpoint URI: /memleak
         */
        [HttpGet]
        public void Index()
        {
            Logger.Info("Init MEM " + GC.GetTotalMemory(false));
            Response.Output.Write("Start Memory Leak Test {0} <br><br>", MemRunHtml);
            Response.Output.Write("Current Memory Bytes: {0} <br>", GC.GetTotalMemory(false));
            Response.Output.Write("Current Memory MB:    {0} <br><br>",
                GC.GetTotalMemory(false) / (1024 * 1024));
        }

        /*
         * Main page for submitting memory allocation
         * Endpoint URI: /memleak/RunMem?MemToConsume=5&MemToAllocate=100
         */
        public void RunMem()
        {
            try
            {
                if (!string.IsNullOrEmpty(Request.QueryString.ToString()))
                {
                    var nameValueCollection = HttpUtility.ParseQueryString(Request.QueryString.ToString());
                    _memToAllocate = long.Parse(nameValueCollection["MemToAllocate"]) * 1000000; // 1 MB
                    _memToConsume = int.Parse(nameValueCollection["MemToConsume"]);
                }

                Response.Output.Write("Memory Leak Test {0} <br><br>", MemClearHtml);

                Response.Output.Write("Memory Leak Test {0} {1:HH:mm:ss} <br>", "Start:", DateTime.Now);
                Response.Output.Write("Current Memory Bytes: {0} <br>", GC.GetTotalMemory(false));
                Response.Output.Write("Current Memory MB:    {0} <br><br>",
                    GC.GetTotalMemory(false) / (1024 * 1024));
                Logger.Info("Start MEM " + GC.GetTotalMemory(false));

                Response.Output.Write(TextareaHeader);
                for (var i = 0; i < _memToConsume; i++)
                {
                    ListToConsume.Add(new byte[_memToAllocate]);
                    Thread.Sleep(100);
                    var mem = GC.GetTotalMemory(false);
                    if (_lastMem == mem) continue;
                    Response.Output.Write("Current Memory Bytes: {0} \n", mem);
                    Response.Output.Write("Current Memory MB:    {0} \n", mem / (1024 * 1024));
                    Logger.Info("Start MEM " + GC.GetTotalMemory(false));
                    _lastMem = mem;
                }

                Response.Output.Write(TextareaFooter);

                Thread.Sleep(100);
                Response.Output.Write("<br><br>Current Memory Bytes: {0} <br>", GC.GetTotalMemory(false));
                Response.Output.Write("Current Memory MB:    {0} <br>",
                    GC.GetTotalMemory(false) / (1024 * 1024));
                Response.Output.Write("Memory Leak Test {0} {1:HH:mm:ss} <br><br><br>", "End:", DateTime.Now);

                Response.Output.Write("Consume Next {0} {1} ",
                    _memToAllocate * _memToConsume / (1024 * 1024) + " MB",
                    MemRunHtml);
                Logger.Info("Start MEM " + GC.GetTotalMemory(false));
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message);
                LogError(ex);
            }
        }

        /*
         * Page to reset (clear) the memory allocation
         * Endpoint URI: /memleak/ClearMem
         */
        public void ClearMem()
        {
            Response.Output.Write("Start Memory Overload Test {0} <br><br>", MemRunHtml);
            ListToConsume.Clear();
            GC.GetTotalMemory(true);
            Thread.Sleep(100);
            Response.Output.Write("<br>Current Memory Bytes: {0} <br>", GC.GetTotalMemory(false));
            Response.Output.Write("Current Memory MB:    {0} <br>",
                GC.GetTotalMemory(false) / (1024 * 1024));
            Response.Output.Write("Memory Overload {0} {1:HH:mm:ss} <br>", "End:", DateTime.Now);
            Logger.Info("Stop MEM " + GC.GetTotalMemory(false));
        }

        private void LogError(Exception ex)
        {
            LogManager.GetLogger(typeof(MvcApplication)).Error(ex);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.