.NET应用程序的未管理堆大小

3
我目前正在尝试对我正在开发的C#项目进行内存分析,以确定是否存在泄漏,因为这个应用程序需要尽可能接近100%的运行时间。 我开始使用Ants Memory Profiler版本7.4,并注意到我的非托管内存随着时间的推移而不断增长,即使我的托管内存没有增加。
经过更多尝试,我尝试在一个仅仅阻塞在Console.ReadLine()指令上的程序上进行类似的分析。我运行了分析并注意到同样的事情发生了。我的非托管堆逐渐增长。实际上,它似乎只会在垃圾收集器被调用(通过快照功能)时增长。为什么重复调用垃圾收集器会导致非托管内存无休止地增加?这与ANTS有关吗?
我想使用其他一些工具,最好是类似于windbg或SOS的工具,来确定它看到的我的非托管内存使用情况。现在并不重要的是我知道里面有什么-虽然这可能有助于长期调试。我只是试图确定当前正在运行的应用程序的非托管内存使用情况。我想看看这是否真的是ANTS的问题还是我对环境工作方式的误解。使用某种.NET、Visual Studio或Windows工具来为我提供有关我的进程的准确信息将有助于解决这个问题。

1
你的代码是100% C#吗?还是有一些C++/CLI或非托管C++的呢? - dario_ramos
1
这是一个Windows窗体项目吗?WindowsForm使用非托管的Window API来绘制对象。 - Draykos
抱歉,我完全忘记了那个至关重要的信息。我没有明确使用任何非托管代码。该代码有一些线程并使用一些 .net 套接字对象。它还作为控制台应用程序运行--其中没有 winform 或 wpf 组件。最后,即使当我模拟了所有 .net 网络对象并且摆脱了我的线程时,我仍然看到了这个问题。同时请注意,对于一个只是在 ReadLine() 上阻塞的单行简单应用程序,我也看到了这种行为。 - user2245290
1
我试图传达的最重要的方面是在一个简单的一行程序中未受管理的内存增长。Console.ReadLine()。在阻塞开始时,根据蚂蚁内存分析器,我的未受管理的内存使用量为2.834 MB。经过42个快照后,我的未受管理的内存增加到3.483 MB。有人能解释一下吗? - user2245290
3个回答

1

AQTime来自SmartBear,非常擅长为您提供托管和非托管代码的内存分析。我的工作很多都在托管和非托管边界上,我已经多次使用它来查找内存泄漏。

如果你正在处理大块非托管内存,请确保调用GC.AddMemoryPressureGC.RemoveMemoryPressure来帮助GC。


我并没有明确地使用非托管内存。所有正在使用的非托管内存都是由于我在使用 .net 托管对象时自动完成的。但还是谢谢,我会看看 AQTime。 - user2245290

0

System.GC.GetTotalMemory(bool) 可能是你正在寻找的。这里是来自链接的注释示例:

using System;
namespace GCCollectIntExample
{
    class MyGCCollectClass
    {
        private const long maxGarbage = 1000;
        static void Main()
        {
            MyGCCollectClass myGCCol = new MyGCCollectClass();

            // Determine the maximum number of generations the system 
        // garbage collector currently supports.
            Console.WriteLine("The highest generation is {0}", GC.MaxGeneration);

            myGCCol.MakeSomeGarbage();

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

            // Determine the best available approximation of the number  
            // of bytes currently allocated in managed memory.
            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

            // Perform a collection of generation 0 only.
            GC.Collect(0);

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

            // Perform a collection of all generations up to and including 2.
            GC.Collect(2);

            // Determine which generation myGCCol object is stored in.
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));
            Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));
            Console.Read();
        }

        void MakeSomeGarbage()
        {
            Version vt;

            for(int i = 0; i < maxGarbage; i++)
            {
                // Create objects and release them to fill up memory 
                // with unused objects.
               vt = new Version();
            }
        }
    }
}

@Robert 是的,我知道。但是我的回答会像这样:回答问题、添加细节、举例说明、澄清、澄清、纠正语法错误、修复他人的答案、获取声望、感觉自己像 Skeet-wanna-be。 - Cole Tobin
1
这与托管内存有关,我的问题与分析非托管内存有关。我上面提到过,我的托管内存并没有随着时间的推移而增长。 - user2245290
你无法确定未受管理的使用情况,因为堆只是一个链表(本质上),没有任何链接到程序使用它的信息。你可以通过确定任务管理器显示的值来获得大致估计。 - Cole Tobin
Cole,顺便提一下。Ants向我提供了我的非托管堆使用情况的摘要。如果我查看任务管理器随时间显示的值,并跟踪这些值-是否能够提供足够准确的信息,以便与Ants给我的内容进行比较/对比?我想看看,实际上,垃圾收集器是否增加了我的内存占用。 - user2245290
2
我可以想象。曾经有人告诉我,平板电脑是内容消费设备,而不是内容生产设备,我恍然大悟。 - Robert Harvey
显示剩余3条评论

0

使用垃圾收集器分析器。如果桶2和3中的对象比1多,则表示您没有正确管理未托管的资源。


如果我的托管内存大小没有增长,并且蚂蚁确认在我的托管内存中没有创建新对象,那么这种方法是否可行来确定我未受管控的堆中的任何信息? - user2245290

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接