翼度科技»论坛 编程开发 .net 查看内容

Advanced .Net Debugging 7:托管堆与垃圾收集

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12

一、简介

    这是我的《Advanced .Net Debugging》这个系列的第七篇文章。这篇文章的内容是原书的第二部分的【调试实战】的第五章,这一章主要讲的是从根本上认识托管堆和垃圾回收。软件系统的内存管理方式有两种,第一种是手动管理内存,这种方式容易产生一些问题产生,比如:悬空指针、重复释放,或者内存泄漏等;第二种是自动内存管理,比如:java 平台、.NET 平台。尽管 GC 能帮助开发人员简化开发工作,让他们更关注系统的业务功能实现。如果我们对 GC 运作原理了解更深入一些,也可以让我们避免在垃圾回收环境中出现的问题。高级调试会涉及很多方面的内容,你对 .NET 基础知识掌握越全面、细节越底层,调试成功的几率越大,当我们遇到各种奇葩问题的时候才不会手足无措。
    如果在没有说明的情况下,所有代码的测试环境都是 Net 8.0,如果有变动,我会在项目章节里进行说明。好了,废话不多说,开始我们今天的调试工作。

     调试环境我需要进行说明,以防大家不清楚,具体情况我已经罗列出来。
          操作系统:Windows Professional 10
          调试工具:Windbg Preview(Debugger Client:1.2306.1401.0,Debugger engine:10.0.25877.1004)和 NTSD(10.0.22621.2428 AMD64)
          下载地址:可以去Microsoft Store 去下载
          开发工具:Microsoft Visual Studio Community 2022 (64 位) - Current版本 17.8.3
          Net 版本:.Net 8.0
          CoreCLR源码:源码下载

    在此说明:我使用了两种调试工具,第一种:Windbg Preivew,图形界面,使用方便,操作顺手,不用担心干扰;第二种是:NTSD,该调试器是命令行的,命令使用上和 Windbg 没有任何区别,之所以增加了它的调试过程,不过是我的个人爱好,想多了解一些,看看他们有什么区别,为了学习而使用的。如果在工作中,我推荐使用 Windbg Preview,更好用,更方便,也不会出现奇怪问题(我在使用 NTSD 调试断点的时候,不能断住,提示内存不可读,Windbg preview 就没有任何问题)。
    如果大家想了解调试过程,二选一即可,当然,我推荐查看【Windbg Preview 调试】。

二、调试源码
    废话不多说,本节是调试的源码部分,没有代码,当然就谈不上测试了,调试必须有载体。
    2.1、ExampleCore_5_1
  1. 1 namespace ExampleCore_5_1
  2. 2 {
  3. 3     internal class Program
  4. 4     {
  5. 5         static void Main(string[] args)
  6. 6         {
  7. 7             Name? name;
  8. 8
  9. 9             Console.WriteLine("Press any key to allocate memory");
  10. 10             Console.ReadKey();
  11. 11
  12. 12             name = new Name("Mario", "Hewardt");
  13. 13
  14. 14             Console.WriteLine("Press any key to Exit");
  15. 15             Console.ReadKey();
  16. 16         }
  17. 17     }
  18. 18
  19. 19     internal class Name
  20. 20     {
  21. 21         private string _first;
  22. 22         private string _last;
  23. 23
  24. 24         public string First { get { return _first; } }
  25. 25
  26. 26         public string Last { get { return _last; } }
  27. 27
  28. 28         public Name(string first, string last)
  29. 29         {
  30. 30             _first = first;
  31. 31             _last = last;
  32. 32         }
  33. 33     }
  34. 34 }
复制代码
View Code
    2.2、ExampleCore_5_2
  1. 1 namespace ExampleCore_5_2
  2. 2 {
  3. 3     internal class Name
  4. 4     {
  5. 5         private string _first;
  6. 6         private string _last;
  7. 7
  8. 8         public string First { get { return _first; } }
  9. 9
  10. 10         public string Last { get { return _last; } }
  11. 11
  12. 12         public Name(string first, string last)
  13. 13         {
  14. 14             _first = first;
  15. 15             _last = last;
  16. 16         }
  17. 17     }
  18. 18
  19. 19     internal class Program
  20. 20     {
  21. 21         static void Main(string[] args)
  22. 22         {
  23. 23             Name? n1 = new Name("Mario", "Hewardt");
  24. 24             Name? n2 = new Name("Gemma", "Hewardt");
  25. 25
  26. 26             Console.WriteLine("allocated objects");
  27. 27
  28. 28             Console.WriteLine("Press any key to invoke GC");
  29. 29             Console.ReadKey();
  30. 30
  31. 31             n1 = null;
  32. 32             GC.Collect();
  33. 33
  34. 34             Console.WriteLine("Press any key to invoke GC");
  35. 35             Console.ReadKey();
  36. 36
  37. 37             GC.Collect();
  38. 38
  39. 39             Console.WriteLine("Press any key to Exit");
  40. 40             Console.ReadKey();
  41. 41         }
  42. 42     }
  43. 43 }
复制代码
View Code
    2.3、ExampleCore_5_3
  1. 1 namespace ExampleCore_5_3
  2. 2 {
  3. 3     internal class Name
  4. 4     {
  5. 5         private string _first;
  6. 6         private string _last;
  7. 7
  8. 8         public string First { get { return _first; } }
  9. 9
  10. 10         public string Last { get { return _last; } }
  11. 11
  12. 12         public Name(string first, string last)
  13. 13         {
  14. 14             _first = first;
  15. 15             _last = last;
  16. 16         }
  17. 17     }
  18. 18
  19. 19     internal class Program
  20. 20     {
  21. 21         public static Name CompleteName = new Name("First", "Last");
  22. 22
  23. 23         private Thread? thread;
  24. 24         private bool shouldExit;
  25. 25         static void Main(string[] args)
  26. 26         {
  27. 27             Program p = new Program();
  28. 28             p.Run();
  29. 29         }
  30. 30
  31. 31         public void Run()
  32. 32         {
  33. 33             shouldExit = false;
  34. 34             Name n1 = CompleteName;
  35. 35
  36. 36             thread = new Thread(Worker);
  37. 37             thread.Start(n1);
  38. 38
  39. 39             Thread.Sleep(1000);
  40. 40
  41. 41             Console.WriteLine("Press any key to Exit");
  42. 42             Console.ReadKey();
  43. 43
  44. 44             shouldExit = true;
  45. 45         }
  46. 46
  47. 47         public void Worker(object? o)
  48. 48         {
  49. 49             var n1 = (Name)o!;
  50. 50             Console.WriteLine("Thread started {0},{1}", n1.First, n1.Last);
  51. 51
  52. 52             while (true)
  53. 53             {
  54. 54                 Thread.Sleep(500);
  55. 55                 if (shouldExit)
  56. 56                 {
  57. 57                     break;
  58. 58                 }
  59. 59             }
  60. 60         }
  61. 61     }
  62. 62 }
复制代码
View Code
    2.4、ExampleCore_5_4
  1. 1 using System.Runtime.InteropServices;
  2. 2
  3. 3 namespace ExampleCore_5_4
  4. 4 {
  5. 5     internal class NativeEvent
  6. 6     {
  7. 7         private IntPtr _nativeHandle;
  8. 8         public IntPtr NativeHandle { get { return _nativeHandle; } }
  9. 9
  10. 10         public NativeEvent(string name)
  11. 11         {
  12. 12             _nativeHandle = CreateEvent(IntPtr.Zero, false, true, name);
  13. 13         }
  14. 14
  15. 15         ~NativeEvent()
  16. 16         {
  17. 17             if (_nativeHandle != IntPtr.Zero)
  18. 18             {
  19. 19                 CloseHandle(_nativeHandle);
  20. 20                 _nativeHandle = IntPtr.Zero;
  21. 21             }
  22. 22         }
  23. 23
  24. 24         [DllImport("kernel32.dll")]
  25. 25         public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool manualReset, bool initialState, string lpName);
  26. 26
  27. 27         [DllImport("kernel32.dll")]
  28. 28         public static extern IntPtr CloseHandle(IntPtr lpEvent);
  29. 29     }
  30. 30
  31. 31     internal class Program
  32. 32     {
  33. 33         static void Main(string[] args)
  34. 34         {
  35. 35             Program p = new Program();
  36. 36             p.Run();
  37. 37         }
  38. 38
  39. 39         public void Run()
  40. 40         {
  41. 41             NativeEvent nativeEvent= new NativeEvent("MyNewEvent");
  42. 42
  43. 43             Console.WriteLine("Press any key to GC1!");
  44. 44             Console.ReadKey();
  45. 45
  46. 46             GC.Collect();
  47. 47
  48. 48             Console.WriteLine("Press any key to GC2!");
  49. 49             Console.ReadKey();
  50. 50
  51. 51             GC.Collect();
  52. 52
  53. 53             Console.WriteLine("Press any key to Exit!");
  54. 54             Console.ReadKey();
  55. 55         }
  56. 56     }
  57. 57 }
复制代码
View Code
    2.5、ExampleCore_5_5
  1. 1 using System.Diagnostics;
  2. 2
  3. 3 namespace ExampleCore_5_5
  4. 4 {
  5. 5     internal class Program
  6. 6     {
  7. 7         static void Main(string[] args)
  8. 8         {
  9. 9             Test();
  10. 10
  11. 11             Console.WriteLine("1、对象已经分配,请查看托管堆!");
  12. 12             Debugger.Break();
  13. 13             GC.Collect();
  14. 14
  15. 15             Console.WriteLine("2、GC 已经触发,请查看托管堆中的 byte2");
  16. 16             Debugger.Break();
  17. 17
  18. 18             Console.WriteLine("3、已分配 byte4,查看是否 Free 块中");
  19. 19             var byte4 = new byte[280000];
  20. 20             Debugger.Break();
  21. 21         }
  22. 22
  23. 23         public static byte[]? byte1;
  24. 24         public static byte[]? byte3;
  25. 25
  26. 26         private static void Test()
  27. 27         {
  28. 28             byte1 = new byte[185000];
  29. 29             var byte2 = new byte[285000];
  30. 30             byte3 = new byte[385000];
  31. 31         }
  32. 32     }
  33. 33 }
复制代码
View Code
    2.7、ExampleCore_5_6
  1. 1 using System.Runtime.InteropServices;
  2. 2
  3. 3 namespace ExampleCore_5_6
  4. 4 {
  5. 5     internal class Program
  6. 6     {
  7. 7         static void Main(string[] args)
  8. 8         {
  9. 9             Program program = new Program();
  10. 10             program.Run();
  11. 11
  12. 12             Console.WriteLine("Press any key to Exit!");
  13. 13             Console.ReadKey();
  14. 14         }
  15. 15
  16. 16         public void Run()
  17. 17         {
  18. 18             sbyte[] b1;
  19. 19             sbyte[] b2;
  20. 20             sbyte[] b3;
  21. 21
  22. 22             Console.WriteLine("Press any key to Alloc And Pinned!");
  23. 23             Console.ReadKey();
  24. 24
  25. 25             b1 = new sbyte[100];
  26. 26             b2 = new sbyte[200];
  27. 27             b3 = new sbyte[300];
  28. 28
  29. 29             GCHandle h1 = GCHandle.Alloc(b1, GCHandleType.Pinned);
  30. 30             GCHandle h2 = GCHandle.Alloc(b2, GCHandleType.Pinned);
  31. 31             GCHandle h3 = GCHandle.Alloc(b3, GCHandleType.Pinned);
  32. 32
  33. 33             Console.WriteLine("Press any key to GC1!");
  34. 34             Console.ReadKey();
  35. 35
  36. 36             GC.Collect();
  37. 37
  38. 38             Console.WriteLine("Press any key to Free!");
  39. 39             Console.ReadKey();
  40. 40
  41. 41             h1.Free();
  42. 42             h2.Free();
  43. 43             h3.Free();
  44. 44
  45. 45             Console.WriteLine("Press any key to GC2!");
  46. 46             Console.ReadKey();
  47. 47
  48. 48             GC.Collect();
  49. 49         }
  50. 50     }
  51. 51 }
复制代码
View Code
    2.8、ExampleCore_5_7
  1. 1 using System.Runtime.InteropServices;
  2. 2
  3. 3 namespace ExampleCore_5_7
  4. 4 {
  5. 5     internal class Program
  6. 6     {
  7. 7         [DllImport("ExampleCore_5_8.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
  8. 8         public extern static int InitChars(char[] chars);
  9. 9
  10. 10         static void Main(string[] args)
  11. 11         {
  12. 12             char[] c = { 'a', 'b', 'c' };
  13. 13             var len = InitChars(c);
  14. 14
  15. 15             GC.Collect();
  16. 16
  17. 17             Console.WriteLine($"len={len}");
  18. 18             for (int i = 0; i < c.Count(); i++)
  19. 19             {
  20. 20                 Console.WriteLine($"{i}={c[i]}");
  21. 21             }
  22. 22             Console.Read();
  23. 23         }
  24. 24     }
  25. 25 }
复制代码
View Code
    2.9、ExampleCore_5_8(C++)
  1. 1 // ExampleCore_5_8.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. 2 //
  3. 3
  4. 4 extern "C"
  5. 5 {
  6. 6     _declspec(dllexport) int InitChars(wchar_t c[]);
  7. 7 }
  8. 8
  9. 9 #include <iostream>
  10. 10 using namespace std;
  11. 11
  12. 12 int InitChars(wchar_t* c)
  13. 13 {
  14. 14     for (size_t i = 0; i < 100; i++)
  15. 15     {
  16. 16         c[i] = L'a';
  17. 17     }
  18. 18     return sizeof(wchar_t) * 100;
  19. 19 }
复制代码
View Code
    2.10、ExampleCore_5_9
  1. 1 using System.Runtime.InteropServices;
  2. 2
  3. 3 namespace ExampleCore_5_9
  4. 4 {
  5. 5     internal class Program
  6. 6     {
  7. 7         static void Main(string[] args)
  8. 8         {
  9. 9             Program program = new Program();
  10. 10             program.Run();
  11. 11         }
  12. 12
  13. 13         public void Run()
  14. 14         {
  15. 15             Console.WriteLine("<alloc size>");
  16. 16             var sizeValue = Console.ReadLine();
  17. 17             if (!int.TryParse(sizeValue, out int size))
  18. 18             {
  19. 19                 Console.WriteLine("参数:<alloc size>!");
  20. 20                 return;
  21. 21             }
  22. 22
  23. 23             Console.WriteLine("<max mem in MB>");
  24. 24             var maxMemValue = Console.ReadLine();
  25. 25             if (!int.TryParse(maxMemValue, out int maxMem))
  26. 26             {
  27. 27                 Console.WriteLine("参数:<max mem in MB>!");
  28. 28                 return;
  29. 29             }
  30. 30
  31. 31             byte[][]? nonPinned = null;
  32. 32             byte[][]? pinned = null;
  33. 33             GCHandle[]? pinnedHandles = null;
  34. 34
  35. 35             int numAllocs = maxMem * 1000000 / size;
  36. 36             pinnedHandles = new GCHandle[numAllocs];
  37. 37
  38. 38             pinned = new byte[numAllocs / 2][];
  39. 39             nonPinned = new byte[numAllocs / 2][];
  40. 40
  41. 41             for (int i = 0; i < numAllocs / 2; i++)
  42. 42             {
  43. 43                 nonPinned[i] = new byte[size];
  44. 44                 pinned[i] = new byte[size];
  45. 45                 pinnedHandles[i] = GCHandle.Alloc(pinned[i], GCHandleType.Pinned);
  46. 46             }
  47. 47
  48. 48             Console.WriteLine("Press any key to GC & promo to gen1");
  49. 49             Console.ReadKey();
  50. 50
  51. 51             GC.Collect();
  52. 52
  53. 53             Console.WriteLine("Press any key to GC & promo to gen2");
  54. 54             Console.ReadKey();
  55. 55
  56. 56             GC.Collect();
  57. 57
  58. 58             Console.WriteLine("Press any key to GC(free non pinned)");
  59. 59             Console.ReadKey();
  60. 60
  61. 61             for (int i = 0; i < numAllocs / 2; i++)
  62. 62             {
  63. 63                 nonPinned[i] = null;
  64. 64             }
  65. 65
  66. 66             GC.Collect();
  67. 67
  68. 68             Console.WriteLine("Press any key to Exit");
  69. 69             Console.ReadKey();
  70. 70         }
  71. 71     }
  72. 72 }
复制代码
View Code
    2.11、ExampleCore_5_10
  1. 1 using System.Xml.Serialization;
  2. 2
  3. 3 namespace ExampleCore_5_10
  4. 4 {
  5. 5     public class Person
  6. 6     {
  7. 7         private string? _name;
  8. 8         private string? _social;
  9. 9         private int _age;
  10. 10
  11. 11         public string? Name
  12. 12         {
  13. 13             get { return _name; }
  14. 14             set { _name = value; }
  15. 15         }
  16. 16
  17. 17         public string? SocialSecurity
  18. 18         {
  19. 19             get { return _social; }
  20. 20             set { _social = value; }
  21. 21         }
  22. 22
  23. 23         public int Age
  24. 24         {
  25. 25             get { return _age; }
  26. 26             set { _age = value; }
  27. 27         }
  28. 28
  29. 29         public Person()
  30. 30         {
  31. 31
  32. 32         }
  33. 33
  34. 34         public Person(string name, string socialSecurity, int age)
  35. 35         {
  36. 36             Name = name;
  37. 37             SocialSecurity = socialSecurity;
  38. 38             Age = age;
  39. 39         }
  40. 40     }
  41. 41
  42. 42     internal class Program
  43. 43     {
  44. 44         static void Main(string[] args)
  45. 45         {
  46. 46             Program program = new Program();
  47. 47             program.Run();
  48. 48             Console.WriteLine("Hello, World!");
  49. 49         }
  50. 50
  51. 51         public void Run()
  52. 52         {
  53. 53             XmlRootAttribute xmlRoot = new XmlRootAttribute();
  54. 54             xmlRoot.ElementName = "MyPersonRoot";
  55. 55             xmlRoot.Namespace = "http://www.contoso.com";
  56. 56             xmlRoot.IsNullable = true;
  57. 57
  58. 58             int index = 0;
  59. 59             while (true)
  60. 60             {
  61. 61
  62. 62                 Person person = new Person();
  63. 63                 person.Name = "Mario Hewardt";
  64. 64                 person.SocialSecurity = "xxx-xx-xxxxxx";
  65. 65                 person.Age = 56;
  66. 66
  67. 67                 XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person), xmlRoot);
  68. 68                 Stream s = new FileStream("F:\\ser.txt", FileMode.Create);
  69. 69
  70. 70                 xmlSerializer.Serialize(s, person);
  71. 71                 s.Close();
  72. 72
  73. 73                 index++;
  74. 74
  75. 75                 Console.WriteLine($"已经序列化第【{index}】个人了!");
  76. 76             }
  77. 77         }
  78. 78     }
  79. 79 }
复制代码
View Code
三、基础知识
    3.1、Windows 内存架构简介

        A、基础知识
            我们先上一张图,来了解一下 Windows 的内存架构。
            


            在用户态(User Mode)中运行的进程通常会使用一个或者多个堆管理器。最常见的堆管理器有两个:Windows 堆管理器和 CLR 堆管理器。
            Windows 堆管理器:它负责满足大多数的内存分配/回收的请求,它从 Windows 虚拟内存管理器中分配大块内存空间(称为内存段(Segment)),并且通过维持特定的记录数据(旁氏列表(Look Aside List)和 空闲列表(Free List)),以一种高效的方式将大块内存空间分割为许多更小的内存块来满足进程的分配需求。
            CLR 堆管理器:和 Windows 堆管理器的功能类似,它为托管进程中所有的内存分配/回收请求提供服务。它同样也是从 Windows 虚拟内存管理器中分配大块内存(也称为内存段),使用这些内存段满足托管系统的内存分配/回收的请求。
            这两种堆管理器的差别就是维持堆完整性时使用的记录数据的结构是不同的。

            CLR 堆管理器有两种运作模式:第一种是工作站模式,第二种是服务器模式
            服务器模式的特点:它有多个堆,堆得数量是和处理器的数量是一致的,并且堆中内存段的大小是比工作站的内存段的大小要大的。
            从 GC 角度来看,两种工作模式是有 GC 线程模型的差异,在服务器模式下,有一个专门的线程管理所有的 GC 的操作,而工作站模式,在执行内存分配的线程上执行 GC 操作。

            堆按对象大小分类:大对象堆(LOH:Large Object Heap)和 小对象堆(SOH:Small Object Heap)。
            大对象堆(LOH):对象的大小等于或者大于 85000 byte 都会分配在大对象堆,>=85000,它有一个初始内存段,大小是16 MB。
            小对象堆(SOH):对象的大小是小于 85000 byte 都会分配在小对象堆上, !DumpHeap  2          Address               MT     Size  3 000001c901400028 00007ff80e0d9df8       96  4 000001c901400088 00007ff80e170a90      128  5 000001c901400108 00007ff80e170b90      128  6 000001c901400188 00007ff80e170c90      128  7 000001c901400208 00007ff80e025fa8       24  8 000001c901400220 00007ff80e1747c8       80  9 000001c901400270 00007ff80e0d9df8       68 10 000001c9014002b8 00007ff80e178ef8      288 11 000001c9014003d8 000001c8fcefc160       24 Free 12 000001c9014003f0 00007ff80e0d9df8     3120 13 000001c901401020 00007ff80e17ad28       24 14 000001c901401038 00007ff80e17bfc8       24 15 000001c901401050 00007ff80e17bfc8       24 16 000001c901401068 00007ff80e17c7d0       24 17 000001c901401080 00007ff80e17c108       24 18 000001c901401098 00007ff80e17ca50       24 19 000001c9014010b0 00007ff80e0dec08       46 20 000001c9014010e0 00007ff80e0dec08      202 21 000001c9014011b0 00007ff80e0dec08       76 22 000001c901401200 000001c8fcefc160       24 Free 23 000001c901401218 00007ff80e0dec08    30224 24 000001c901408828 00007ff80e0dec08       80 25 000001c901408878 00007ff80e0dec08      142 26 000001c901408908 00007ff80e0dec08       68 27 000001c901408950 00007ff80e0dec08       74 28 000001c9014089a0 00007ff80e0dec08      232 29 000001c901408a88 00007ff80e0dec08       66 30 000001c901408ad0 00007ff80e0dec08      468 31 000001c901408ca8 00007ff80e0dec08       60 32 000001c901408ce8 00007ff80e0dec08       58 33 000001c901408d28 00007ff80e0dec08       36 34 000001c901408d50 00007ff80e0dec08      160 35 000001c901408df0 00007ff80e0dec08       32 36 000001c901408e10 00007ff80e0dec08       64 37 000001c901408e50 00007ff80e0dec08       48 38 000001c901408e80 00007ff80e17fa90       32 39 000001c901408ea0 00007ff80e17fa90       24 40 000001c901408eb8 00007ff80e0dec08      274 41 000001c901408fd0 00007ff80e1a21f0      400 42 000001c901409160 00007ff80e1a2320       24 43 000001c901409178 00007ff80e1a23f8      104 44 000001c9014091e0 00007ff80e1a3020       32 45 000001c901409200 00007ff80e1a2b10       64 46 000001c901409240 00007ff80e1a3a08       88 47 000001c901409298 00007ff80e1a3ce8       24 48 000001c9014092b0 00007ff80e1a2b10       64 49 000001c9014092f0 00007ff80e1a37a0       64 50 000001c901409330 00007ff80e1a3ce8       24 51 000001c901409348 00007ff80e1a62e8       32 52 000001c901409368 00007ff80e1a71c8       40 53 000001c901409390 00007ff80e1a85b8      184 54 000001c901409448 00007ff80e1a2320       24 55 000001c901409460 00007ff80e1a23f8      104 56 000001c9014094c8 00007ff80e1a2b10       64 57 000001c901409508 00007ff80e1a3a08       88 58 000001c901409560 00007ff80e1a3ce8       24 59 000001c901409578 00007ff80e1a2b10       64 60 000001c9014095b8 00007ff80e1a37a0       64 61 000001c9014095f8 00007ff80e1a3ce8       24 62 000001c901409610 00007ff80e1a56e0       24 63 000001c901409628 00007ff80e1a56e0       24 64 000001c901409640 00007ff80e025fa8       24 65 000001c901409658 00007ff80e0dec08       46 66 000001c901409688 00007ff80e1d0278       48 67 000001c9014096b8 00007ff80e1d1e90       48 68 000001c9014096e8 00007ff80e1d24a8       24 69 000001c901409700 00007ff80e1d2220       24 70 000001c901409718 00007ff80e1d0c28       64 71 000001c901409758 00007ff80e1d24a8       24 72 000001c901409770 00007ff80e1d2220       24 73 000001c901409788 00007ff80e0dec08       46 74 000001c9014097b8 00007ff80e0dec08       46 75 000001c9014097e8 00007ff80e1d31c8       48 76 000001c901409818 00007ff80e0dec08       46 77 000001c901409848 00007ff80e1d96e8       24 78 000001c901409860 00007ff80e1d9218      104 79 000001c9014098c8 00007ff80e025fa8       24 80 000001c9014098e0 00007ff80e1dcea0       40 81 000001c901409908 00007ff80e1dddf0       72 82 000001c901409950 00007ff80e1dc008       64 83 000001c901409990 00007ff80e1de1f8       24 84 000001c9014099a8 00007ff80e1de618       40 85 000001c9014099d0 00007ff80e1de958       28 86 000001c9014099f0 00007ff80e1f13b0       48 87 000001c901409a20 00007ff80e1de958      536 88 000001c901409c38 00007ff80e1f3530       48 89 000001c901409c68 00007ff80e0dec08       46 90 000001c901409c98 00007ff80e025fa8       24 91 000001c901409cb0 00007ff80e0dec08       46 92 0000020993620008 00007ff80e0dec08       24 93 0000020993620020 00007ff80e02a318       40 94 0000020993620048 00007ff80e0dec08      150 95 00000209936200e0 00007ff80e0dec08      122 96 0000020993620160 00007ff80e0dec08       42 97 0000020993620190 00007ff80e0dec08       30 98 00000209936201b0 00007ff80e0dec08       50 99 00000209936201e8 00007ff80e0dec08       38100 0000020993620210 00007ff80e0dec08       26101 0000020993620230 00007ff80e0dec08       34102 0000020993620258 00007ff80e0dec08      118103 00000209936202d0 00007ff80e0dec08      126104 0000020993620350 00007ff80e1a1800       32105 0000020993620370 00007ff80e0dec08       30106 0000020993620390 00007ff80e0dec08       32107 00000209936203b0 00007ff80e0dec08       84108 0000020993620408 00007ff80e0dec08       98109 0000020993620470 00007ff80e0dec08       48110 00000209936204a0 00007ff80e0dec08       86111 00000209936204f8 00007ff80e0dec08       32112 0000020993620518 00007ff80e0dec08       36113 0000020993620540 00007ff80e0dec08       64114 0000020993620580 00007ff80e0dec08      112115 00000209936205f0 00007ff80e0dec08       38116 0000020993620618 00007ff80e0dec08       90117 0000020993620678 00007ff80e0dec08       42118 00000209936206a8 00007ff80e0dec08      104119 0000020993620710 00007ff80e0dec08      130120 0000020993620798 00007ff80e0dec08      160121 0000020993620838 00007ff80e0dec08      124122 00000209936208b8 00007ff80e0dec08       38123 00000209936208e0 00007ff80e0dec08       24124 00000209936208f8 00007ff80e0dec08       44125 0000020993620928 00007ff80e0dec08       24126 0000020993620940 00007ff80e1d9ff8       24127 0000020993620958 00007ff80e0dec08       26128 0000020993620978 00007ff80e0dec08       42129 00000209936209a8 00007ff80e0dec08       40130 00000209936209d0 00007ff80e0dec08       32131 00000209936209f0 00007ff80e0dec08       32132 0000020993620a10 00007ff80e0dec08       40133 0000020993620a38 00007ff80e0dec08       34134 0000020993620a60 00007ff80e1adfe0       40135 000001c8fec00028 00007ff80e02c4d8     8184136 000001c8fec02020 00007ff80e02c4d8     8184137 138 Statistics:139               MT    Count    TotalSize Class Name140 00007ff80e1de1f8        1           24 System.Threading.Tasks.Task+c141 00007ff80e1d9ff8        1           24 System.Byte[]142 00007ff80e1d96e8        1           24 System.IO.Stream+NullStream143 00007ff80e17ca50        1           24 System.OrdinalIgnoreCaseComparer144 00007ff80e17c7d0        1           24 System.OrdinalCaseSensitiveComparer145 00007ff80e17c108        1           24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer146 00007ff80e17ad28        1           24 System.Collections.Generic.GenericEqualityComparer`1[[System.String, System.Private.CoreLib]]147 00007ff80e1a62e8        1           32 System.Collections.Generic.List`1[[System.WeakReference`1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]], System.Private.CoreLib]]148 00007ff80e1a3020        1           32 System.Diagnostics.Tracing.ActivityTracker149 00007ff80e1a1800        1           32 System.Guid150 00007ff80e1de618        1           40 System.IO.TextWriter+NullTextWriter151 00007ff80e1dcea0        1           40 System.Threading.Tasks.TaskFactory152 00007ff80e1adfe0        1           40 Interop+INPUT_RECORD153 00007ff80e1a71c8        1           40 System.WeakReference`1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]][]154 00007ff80e02a318        1           40 System.RuntimeType155 00007ff80e1f3530        1           48 System.IO.TextWriter+SyncTextWriter156 00007ff80e1f13b0        1           48 System.Text.OSEncoder157 00007ff80e1d31c8        1           48 System.ConsolePal+WindowsConsoleStream158 00007ff80e1d24a8        2           48 System.Text.EncoderReplacementFallback159 00007ff80e1d2220        2           48 System.Text.DecoderReplacementFallback160 00007ff80e1d1e90        1           48 System.Text.UTF8Encoding+UTF8EncodingSealed161 00007ff80e1d0278        1           48 System.Reflection.RuntimeAssembly162 00007ff80e1a56e0        2           48 System.WeakReference`1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]]163 00007ff80e1a2320        2           48 System.Diagnostics.Tracing.TraceLoggingEventHandleTable164 00007ff80e17bfc8        2           48 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalComparer165 000001c8fcefc160        2           48      Free166 00007ff80e17fa90        2           56 System.String[]167 00007ff80e1dc008        1           64 System.Threading.ContextCallback168 00007ff80e1d0c28        1           64 System.Text.OSEncoding169 00007ff80e1dddf0        1           72 System.Threading.Tasks.Task`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib]]170 00007ff80e1747c8        1           80 System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.Object, System.Private.CoreLib]]171 00007ff80e1a3ce8        4           96 System.WeakReference`1[[System.Diagnostics.Tracing.EventProvider, System.Private.CoreLib]]172 00007ff80e025fa8        4           96 System.Object173 00007ff80e1d9218        1          104 System.IO.StreamWriter174 00007ff80e1a37a0        2          128 System.Diagnostics.Tracing.EventPipeEventProvider175 00007ff80e170c90        1          128 System.ExecutionEngineException176 00007ff80e170b90        1          128 System.StackOverflowException177 00007ff80e170a90        1          128 System.OutOfMemoryException178 00007ff80e1a3a08        2          176 System.Diagnostics.Tracing.EtwEventProvider179 00007ff80e1a85b8        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource180 00007ff80e1a23f8        2          208 System.IntPtr[]181 00007ff80e1a2b10        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider182 00007ff80e178ef8        1          288 System.Collections.Generic.Dictionary`2+Entry[[System.String, System.Private.CoreLib],[System.Object, System.Private.CoreLib]][]183 00007ff80e1a21f0        1          400 System.Diagnostics.Tracing.RuntimeEventSource184 00007ff80e1de958        2          564 System.Char[]185 00007ff80e0d9df8        3         3284 System.Int32[]186 00007ff80e02c4d8        2        16368 System.Object[]187 00007ff80e0dec08       64        35132 System.String[/code]                输出包含两个部分,第一部分输出了在当前托管堆中所有的对象,包括对象的地址、方法表和大小。我们有了对象的地址,就可以使用【!DumpObj】命令查看对象的详情。
  1.   1 0:002> !DumpHeap
  2.   2          Address               MT     Size
  3.   3 000001c901400028 00007ff80e0d9df8       96
  4.   4 000001c901400088 00007ff80e170a90      128
  5.   5 000001c901400108 00007ff80e170b90      128
  6.   6 000001c901400188 00007ff80e170c90      128
  7.   7 000001c901400208 00007ff80e025fa8       24
  8.   8 000001c901400220 00007ff80e1747c8       80
  9.   9 000001c901400270 00007ff80e0d9df8       68
  10. 10 000001c9014002b8 00007ff80e178ef8      288
  11. 11 000001c9014003d8 000001c8fcefc160       24 Free
  12. 12 000001c9014003f0 00007ff80e0d9df8     3120
  13. 13 000001c901401020 00007ff80e17ad28       24
  14. 14 000001c901401038 00007ff80e17bfc8       24
  15. 15 000001c901401050 00007ff80e17bfc8       24
  16. 16 000001c901401068 00007ff80e17c7d0       24
  17. 17 000001c901401080 00007ff80e17c108       24
  18. 18 000001c901401098 00007ff80e17ca50       24
  19. 19 000001c9014010b0 00007ff80e0dec08       46
  20. 20 000001c9014010e0 00007ff80e0dec08      202
  21. 21 000001c9014011b0 00007ff80e0dec08       76
  22. 22 000001c901401200 000001c8fcefc160       24 Free
  23. 23 000001c901401218 00007ff80e0dec08    30224
  24. 24 000001c901408828 00007ff80e0dec08       80
  25. 25 000001c901408878 00007ff80e0dec08      142
  26. 26 000001c901408908 00007ff80e0dec08       68
  27. 27 000001c901408950 00007ff80e0dec08       74
  28. 28 000001c9014089a0 00007ff80e0dec08      232
  29. 29 000001c901408a88 00007ff80e0dec08       66
  30. 30 000001c901408ad0 00007ff80e0dec08      468
  31. 31 000001c901408ca8 00007ff80e0dec08       60
  32. 32 000001c901408ce8 00007ff80e0dec08       58
  33. 33 000001c901408d28 00007ff80e0dec08       36
  34. 34 000001c901408d50 00007ff80e0dec08      160
  35. 35 000001c901408df0 00007ff80e0dec08       32
  36. 36 000001c901408e10 00007ff80e0dec08       64
  37. 37 000001c901408e50 00007ff80e0dec08       48
  38. 38 000001c901408e80 00007ff80e17fa90       32
  39. 39 000001c901408ea0 00007ff80e17fa90       24
  40. 40 000001c901408eb8 00007ff80e0dec08      274
  41. 41 000001c901408fd0 00007ff80e1a21f0      400
  42. 42 000001c901409160 00007ff80e1a2320       24
  43. 43 000001c901409178 00007ff80e1a23f8      104
  44. 44 000001c9014091e0 00007ff80e1a3020       32
  45. 45 000001c901409200 00007ff80e1a2b10       64
  46. 46 000001c901409240 00007ff80e1a3a08       88
  47. 47 000001c901409298 00007ff80e1a3ce8       24
  48. 48 000001c9014092b0 00007ff80e1a2b10       64
  49. 49 000001c9014092f0 00007ff80e1a37a0       64
  50. 50 000001c901409330 00007ff80e1a3ce8       24
  51. 51 000001c901409348 00007ff80e1a62e8       32
  52. 52 000001c901409368 00007ff80e1a71c8       40
  53. 53 000001c901409390 00007ff80e1a85b8      184
  54. 54 000001c901409448 00007ff80e1a2320       24
  55. 55 000001c901409460 00007ff80e1a23f8      104
  56. 56 000001c9014094c8 00007ff80e1a2b10       64
  57. 57 000001c901409508 00007ff80e1a3a08       88
  58. 58 000001c901409560 00007ff80e1a3ce8       24
  59. 59 000001c901409578 00007ff80e1a2b10       64
  60. 60 000001c9014095b8 00007ff80e1a37a0       64
  61. 61 000001c9014095f8 00007ff80e1a3ce8       24
  62. 62 000001c901409610 00007ff80e1a56e0       24
  63. 63 000001c901409628 00007ff80e1a56e0       24
  64. 64 000001c901409640 00007ff80e025fa8       24
  65. 65 000001c901409658 00007ff80e0dec08       46
  66. 66 000001c901409688 00007ff80e1d0278       48
  67. 67 000001c9014096b8 00007ff80e1d1e90       48
  68. 68 000001c9014096e8 00007ff80e1d24a8       24
  69. 69 000001c901409700 00007ff80e1d2220       24
  70. 70 000001c901409718 00007ff80e1d0c28       64
  71. 71 000001c901409758 00007ff80e1d24a8       24
  72. 72 000001c901409770 00007ff80e1d2220       24
  73. 73 000001c901409788 00007ff80e0dec08       46
  74. 74 000001c9014097b8 00007ff80e0dec08       46
  75. 75 000001c9014097e8 00007ff80e1d31c8       48
  76. 76 000001c901409818 00007ff80e0dec08       46
  77. 77 000001c901409848 00007ff80e1d96e8       24
  78. 78 000001c901409860 00007ff80e1d9218      104
  79. 79 000001c9014098c8 00007ff80e025fa8       24
  80. 80 000001c9014098e0 00007ff80e1dcea0       40
  81. 81 000001c901409908 00007ff80e1dddf0       72
  82. 82 000001c901409950 00007ff80e1dc008       64
  83. 83 000001c901409990 00007ff80e1de1f8       24
  84. 84 000001c9014099a8 00007ff80e1de618       40
  85. 85 000001c9014099d0 00007ff80e1de958       28
  86. 86 000001c9014099f0 00007ff80e1f13b0       48
  87. 87 000001c901409a20 00007ff80e1de958      536
  88. 88 000001c901409c38 00007ff80e1f3530       48
  89. 89 000001c901409c68 00007ff80e0dec08       46
  90. 90 000001c901409c98 00007ff80e025fa8       24
  91. 91 000001c901409cb0 00007ff80e0dec08       46
  92. 92 0000020993620008 00007ff80e0dec08       24
  93. 93 0000020993620020 00007ff80e02a318       40
  94. 94 0000020993620048 00007ff80e0dec08      150
  95. 95 00000209936200e0 00007ff80e0dec08      122
  96. 96 0000020993620160 00007ff80e0dec08       42
  97. 97 0000020993620190 00007ff80e0dec08       30
  98. 98 00000209936201b0 00007ff80e0dec08       50
  99. 99 00000209936201e8 00007ff80e0dec08       38
  100. 100 0000020993620210 00007ff80e0dec08       26
  101. 101 0000020993620230 00007ff80e0dec08       34
  102. 102 0000020993620258 00007ff80e0dec08      118
  103. 103 00000209936202d0 00007ff80e0dec08      126
  104. 104 0000020993620350 00007ff80e1a1800       32
  105. 105 0000020993620370 00007ff80e0dec08       30
  106. 106 0000020993620390 00007ff80e0dec08       32
  107. 107 00000209936203b0 00007ff80e0dec08       84
  108. 108 0000020993620408 00007ff80e0dec08       98
  109. 109 0000020993620470 00007ff80e0dec08       48
  110. 110 00000209936204a0 00007ff80e0dec08       86
  111. 111 00000209936204f8 00007ff80e0dec08       32
  112. 112 0000020993620518 00007ff80e0dec08       36
  113. 113 0000020993620540 00007ff80e0dec08       64
  114. 114 0000020993620580 00007ff80e0dec08      112
  115. 115 00000209936205f0 00007ff80e0dec08       38
  116. 116 0000020993620618 00007ff80e0dec08       90
  117. 117 0000020993620678 00007ff80e0dec08       42
  118. 118 00000209936206a8 00007ff80e0dec08      104
  119. 119 0000020993620710 00007ff80e0dec08      130
  120. 120 0000020993620798 00007ff80e0dec08      160
  121. 121 0000020993620838 00007ff80e0dec08      124
  122. 122 00000209936208b8 00007ff80e0dec08       38
  123. 123 00000209936208e0 00007ff80e0dec08       24
  124. 124 00000209936208f8 00007ff80e0dec08       44
  125. 125 0000020993620928 00007ff80e0dec08       24
  126. 126 0000020993620940 00007ff80e1d9ff8       24
  127. 127 0000020993620958 00007ff80e0dec08       26
  128. 128 0000020993620978 00007ff80e0dec08       42
  129. 129 00000209936209a8 00007ff80e0dec08       40
  130. 130 00000209936209d0 00007ff80e0dec08       32
  131. 131 00000209936209f0 00007ff80e0dec08       32
  132. 132 0000020993620a10 00007ff80e0dec08       40
  133. 133 0000020993620a38 00007ff80e0dec08       34
  134. 134 0000020993620a60 00007ff80e1adfe0       40
  135. 135 000001c8fec00028 00007ff80e02c4d8     8184
  136. 136 000001c8fec02020 00007ff80e02c4d8     8184
  137. 137
  138. 138 Statistics:
  139. 139               MT    Count    TotalSize Class Name
  140. 140 00007ff80e1de1f8        1           24 System.Threading.Tasks.Task+<>c
  141. 141 00007ff80e1d9ff8        1           24 System.Byte[]
  142. 142 00007ff80e1d96e8        1           24 System.IO.Stream+NullStream
  143. 143 00007ff80e17ca50        1           24 System.OrdinalIgnoreCaseComparer
  144. 144 00007ff80e17c7d0        1           24 System.OrdinalCaseSensitiveComparer
  145. 145 00007ff80e17c108        1           24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer
  146. 146 00007ff80e17ad28        1           24 System.Collections.Generic.GenericEqualityComparer`1[[System.String, System.Private.CoreLib]]
  147. 147 00007ff80e1a62e8        1           32 System.Collections.Generic.List`1[[System.WeakReference`1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]], System.Private.CoreLib]]
  148. 148 00007ff80e1a3020        1           32 System.Diagnostics.Tracing.ActivityTracker
  149. 149 00007ff80e1a1800        1           32 System.Guid
  150. 150 00007ff80e1de618        1           40 System.IO.TextWriter+NullTextWriter
  151. 151 00007ff80e1dcea0        1           40 System.Threading.Tasks.TaskFactory
  152. 152 00007ff80e1adfe0        1           40 Interop+INPUT_RECORD
  153. 153 00007ff80e1a71c8        1           40 System.WeakReference`1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]][]
  154. 154 00007ff80e02a318        1           40 System.RuntimeType
  155. 155 00007ff80e1f3530        1           48 System.IO.TextWriter+SyncTextWriter
  156. 156 00007ff80e1f13b0        1           48 System.Text.OSEncoder
  157. 157 00007ff80e1d31c8        1           48 System.ConsolePal+WindowsConsoleStream
  158. 158 00007ff80e1d24a8        2           48 System.Text.EncoderReplacementFallback
  159. 159 00007ff80e1d2220        2           48 System.Text.DecoderReplacementFallback
  160. 160 00007ff80e1d1e90        1           48 System.Text.UTF8Encoding+UTF8EncodingSealed
  161. 161 00007ff80e1d0278        1           48 System.Reflection.RuntimeAssembly
  162. 162 00007ff80e1a56e0        2           48 System.WeakReference`1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]]
  163. 163 00007ff80e1a2320        2           48 System.Diagnostics.Tracing.TraceLoggingEventHandleTable
  164. 164 00007ff80e17bfc8        2           48 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalComparer
  165. 165 000001c8fcefc160        2           48      Free
  166. 166 00007ff80e17fa90        2           56 System.String[]
  167. 167 00007ff80e1dc008        1           64 System.Threading.ContextCallback
  168. 168 00007ff80e1d0c28        1           64 System.Text.OSEncoding
  169. 169 00007ff80e1dddf0        1           72 System.Threading.Tasks.Task`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib]]
  170. 170 00007ff80e1747c8        1           80 System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
  171. 171 00007ff80e1a3ce8        4           96 System.WeakReference`1[[System.Diagnostics.Tracing.EventProvider, System.Private.CoreLib]]
  172. 172 00007ff80e025fa8        4           96 System.Object
  173. 173 00007ff80e1d9218        1          104 System.IO.StreamWriter
  174. 174 00007ff80e1a37a0        2          128 System.Diagnostics.Tracing.EventPipeEventProvider
  175. 175 00007ff80e170c90        1          128 System.ExecutionEngineException
  176. 176 00007ff80e170b90        1          128 System.StackOverflowException
  177. 177 00007ff80e170a90        1          128 System.OutOfMemoryException
  178. 178 00007ff80e1a3a08        2          176 System.Diagnostics.Tracing.EtwEventProvider
  179. 179 00007ff80e1a85b8        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  180. 180 00007ff80e1a23f8        2          208 System.IntPtr[]
  181. 181 00007ff80e1a2b10        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  182. 182 00007ff80e178ef8        1          288 System.Collections.Generic.Dictionary`2+Entry[[System.String, System.Private.CoreLib],[System.Object, System.Private.CoreLib]][]
  183. 183 00007ff80e1a21f0        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  184. 184 00007ff80e1de958        2          564 System.Char[]
  185. 185 00007ff80e0d9df8        3         3284 System.Int32[]
  186. 186 00007ff80e02c4d8        2        16368 System.Object[]
  187. 187 00007ff80e0dec08       64        35132 System.String
复制代码
                【!DumpObj】命令还有一个变体就是【!do】,输出结果是一样的。
  1. 1 0:002> !DumpObj 000001c901400028
  2. 2 Name:        System.Int32[]
  3. 3 MethodTable: 00007ff80e0d9df8
  4. 4 EEClass:     00007ff80e0d9d78
  5. 5 Tracked Type: false
  6. 6 Size:        96(0x60) bytes
  7. 7 Array:       Rank 1, Number of elements 18, Type Int32
  8. 8 Fields:
复制代码
                【!DumpHeap】命令输出的第二部分包含了有关托管堆行为的统计信息,其中相关的对象被分为一组,给出了这组对象的方法表地址、实例个数、总体大小和对象的类型名称。
                【!DumpHeap】命令不跟任何参数,输出内容太多,我们可以使用它的命令开关进行过滤,比如:-type、-mt 还有很多,可以自己去尝试。-type 可以在托管堆上查找指定的类型名,-mt 可以查找指定的方法表。
                我们使用【!DumpHeap -type ExampleCore_5_1.Name】命令,查找 Name 类型。
  1. 1 0:002> !do 000001c901400028
  2. 2 Name:        System.Int32[]
  3. 3 MethodTable: 00007ff80e0d9df8
  4. 4 EEClass:     00007ff80e0d9d78
  5. 5 Tracked Type: false
  6. 6 Size:        96(0x60) bytes
  7. 7 Array:       Rank 1, Number of elements 18, Type Int32
  8. 8 Fields:
  9. 9 None
复制代码
                什么也没输出,因为在托管堆上还没有该对象。
                此时,我们继续运行【g】调试器,直到调试器输出如图:
                

                我们继续按【ctrl+c】组合键,进入中断模式,再次执行【!DumpHeap -type ExampleCore_5_1.Name】命令,这次输出不同了。
  1. 1 0:002> !DumpHeap -type ExampleCore_5_1_1.Name
  2. 2          Address               MT     Size
  3. 3
  4. 4 Statistics:
  5. 5               MT    Count    TotalSize Class Name
  6. 6 Total 0 objects
复制代码
                输出的结果和【!DumpHeap】命令的默认输出类似,首相给出特定实例的特定数据(地址、方法表和大小),最后就是统计信息,在托管堆上只有一个这样的实例、大小、类型名和方法表的地址。

            2)、Windbg Preview 调试
                编译项目,打开【Windbg Preview】调试器,依次点击【文件】---【Launch executable】,加载我们的项目文件:ExampleCore_5_1.exe。进入调试器,我们使用【g】命令,继续运行调试器,直到我们的控制台程序输出“Press any key to allocate memory”这样的文字,点击调试器中【break】按钮,中断调试器的执行。
                此时,我们就可以执行【!DumpHeap】命令,查看一下托管堆上有什么东西,内容还是不少的。
  1. 1 0:002> !DumpHeap -type ExampleCore_5_1.Name
  2. 2          Address               MT     Size
  3. 3 000001c901409ce0 00007ff80e1a9418       32
  4. 4
  5. 5 Statistics:
  6. 6               MT    Count    TotalSize Class Name
  7. 7 00007ff80e1a9418        1           32 ExampleCore_5_1.Name
  8. 8 Total 1 objects
复制代码
                为了让大家看的更清楚,我没有省略,如果是第一次查看,完全的更好的,能有一个更直观的感受。
                【!DumpHeap】命令的输出分为两个部分。第一个部分包含了位于当前托管堆中的所有对象。对于任何一个对象,都可以使用【!DumpObj】命令或者【!do】查看对象的详情。
                第二部分包含了托管堆行为的统计信息,其中相关的对象会被分为一组,并给出了这组对象的方法表、对象数量、总体大小和对象的类型名。如图:
                

                表示对象是 System.Collections.Generic.GenericEqualityComparer 类型,方法表位于 7ff80668ad28,在托管堆中共有1个实例,总大小为 24 个字节。
                在分析一个很大的托管堆以及需要找出哪些对象导致了堆空间的增长时,这些统计信息非常有用。
                【!DumpHeap】命令不跟任何参数,输出的内容太多了,如果我们想找一些特定的信息就比较难。该命令提供了许多开关选项可以帮助我们。-type、-mt 这两个开关可以帮助我们在托管堆中查找指定的类型名或者方法表的地址。
  1.   1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes.
  34.   2          Address               MT           Size
  35.   3     025e5a800028     7ff80653c4d8          8,184
  36.   4     025e5a802020     7ff80653c4d8          8,184
  37.   5     025e5d000028     7ff8065e9df8             96
  38.   6     025e5d000088     7ff806680a90            128
  39.   7     025e5d000108     7ff806680b90            128
  40.   8     025e5d000188     7ff806680c90            128
  41.   9     025e5d000208     7ff806535fa8             24
  42. 10     025e5d000220     7ff8066847c8             80
  43. 11     025e5d000270     7ff8065e9df8             68
  44. 12     025e5d0002b8     7ff806688ef8            288
  45. 13     025e5d0003d8     025e588f79b0             24 Free
  46. 14     025e5d0003f0     7ff8065e9df8          3,120
  47. 15     025e5d001020     7ff80668ad28             24
  48. 16     025e5d001038     7ff80668bfc8             24
  49. 17     025e5d001050     7ff80668bfc8             24
  50. 18     025e5d001068     7ff80668c7d0             24
  51. 19     025e5d001080     7ff80668c108             24
  52. 20     025e5d001098     7ff80668ca50             24
  53. 21     025e5d0010b0     7ff8065eec08             46
  54. 22     025e5d0010e0     7ff8065eec08            202
  55. 23     025e5d0011b0     7ff8065eec08             76
  56. 24     025e5d001200     025e588f79b0             24 Free
  57. 25     025e5d001218     7ff8065eec08         30,224
  58. 26     025e5d008828     7ff8065eec08             80
  59. 27     025e5d008878     7ff8065eec08            142
  60. 28     025e5d008908     7ff8065eec08             68
  61. 29     025e5d008950     7ff8065eec08             74
  62. 30     025e5d0089a0     7ff8065eec08            232
  63. 31     025e5d008a88     7ff8065eec08             66
  64. 32     025e5d008ad0     7ff8065eec08            468
  65. 33     025e5d008ca8     7ff8065eec08             60
  66. 34     025e5d008ce8     7ff8065eec08             58
  67. 35     025e5d008d28     7ff8065eec08             36
  68. 36     025e5d008d50     7ff8065eec08            160
  69. 37     025e5d008df0     7ff8065eec08             32
  70. 38     025e5d008e10     7ff8065eec08             64
  71. 39     025e5d008e50     7ff8065eec08             48
  72. 40     025e5d008e80     7ff80668fa90             32
  73. 41     025e5d008ea0     7ff80668fa90             24
  74. 42     025e5d008eb8     7ff8065eec08            274
  75. 43     025e5d008fd0     7ff8066b21f0            400
  76. 44     025e5d009160     7ff8066b2320             24
  77. 45     025e5d009178     7ff8066b23f8            104
  78. 46     025e5d0091e0     7ff8066b3020             32
  79. 47     025e5d009200     7ff8066b2b10             64
  80. 48     025e5d009240     7ff8066b3a08             88
  81. 49     025e5d009298     7ff8066b3ce8             24
  82. 50     025e5d0092b0     7ff8066b2b10             64
  83. 51     025e5d0092f0     7ff8066b37a0             64
  84. 52     025e5d009330     7ff8066b3ce8             24
  85. 53     025e5d009348     7ff8066b62e8             32
  86. 54     025e5d009368     7ff8066b71c8             40
  87. 55     025e5d009390     7ff8066b85b8            184
  88. 56     025e5d009448     7ff8066b2320             24
  89. 57     025e5d009460     7ff8066b23f8            104
  90. 58     025e5d0094c8     7ff8066b2b10             64
  91. 59     025e5d009508     7ff8066b3a08             88
  92. 60     025e5d009560     7ff8066b3ce8             24
  93. 61     025e5d009578     7ff8066b2b10             64
  94. 62     025e5d0095b8     7ff8066b37a0             64
  95. 63     025e5d0095f8     7ff8066b3ce8             24
  96. 64     025e5d009610     7ff8066b56e0             24
  97. 65     025e5d009628     7ff8066b56e0             24
  98. 66     025e5d009640     7ff806535fa8             24
  99. 67     025e5d009658     7ff8065eec08             46
  100. 68     025e5d009688     7ff8066e0278             48
  101. 69     025e5d0096b8     7ff8066e1e90             48
  102. 70     025e5d0096e8     7ff8066e24a8             24
  103. 71     025e5d009700     7ff8066e2220             24
  104. 72     025e5d009718     7ff8066e0c28             64
  105. 73     025e5d009758     7ff8066e24a8             24
  106. 74     025e5d009770     7ff8066e2220             24
  107. 75     025e5d009788     7ff8065eec08             46
  108. 76     025e5d0097b8     7ff8065eec08             46
  109. 77     025e5d0097e8     7ff8066e31c8             48
  110. 78     025e5d009818     7ff8065eec08             46
  111. 79     025e5d009848     7ff8066e96e8             24
  112. 80     025e5d009860     7ff8066e9218            104
  113. 81     025e5d0098c8     7ff806535fa8             24
  114. 82     025e5d0098e0     7ff8066ecea0             40
  115. 83     025e5d009908     7ff8066eddf0             72
  116. 84     025e5d009950     7ff8066ec008             64
  117. 85     025e5d009990     7ff8066ee1f8             24
  118. 86     025e5d0099a8     7ff8066ee618             40
  119. 87     025e5d0099d0     7ff8066ee958             28
  120. 88     025e5d0099f0     7ff8067013b0             48
  121. 89     025e5d009a20     7ff8066ee958            536
  122. 90     025e5d009c38     7ff806703530             48
  123. 91     025e5d009c68     7ff8065eec08             46
  124. 92     025e5d009c98     7ff806535fa8             24
  125. 93     025e5d009cb0     7ff8065eec08             46
  126. 94     029eeef70008     7ff8065eec08             24
  127. 95     029eeef70020     7ff80653a318             40
  128. 96     029eeef70048     7ff8065eec08            150
  129. 97     029eeef700e0     7ff8065eec08            122
  130. 98     029eeef70160     7ff8065eec08             42
  131. 99     029eeef70190     7ff8065eec08             30
  132. 100     029eeef701b0     7ff8065eec08             50
  133. 101     029eeef701e8     7ff8065eec08             38
  134. 102     029eeef70210     7ff8065eec08             26
  135. 103     029eeef70230     7ff8065eec08             34
  136. 104     029eeef70258     7ff8065eec08            118
  137. 105     029eeef702d0     7ff8065eec08            126
  138. 106     029eeef70350     7ff8066b1800             32
  139. 107     029eeef70370     7ff8065eec08             30
  140. 108     029eeef70390     7ff8065eec08             32
  141. 109     029eeef703b0     7ff8065eec08             84
  142. 110     029eeef70408     7ff8065eec08             98
  143. 111     029eeef70470     7ff8065eec08             48
  144. 112     029eeef704a0     7ff8065eec08             86
  145. 113     029eeef704f8     7ff8065eec08             32
  146. 114     029eeef70518     7ff8065eec08             36
  147. 115     029eeef70540     7ff8065eec08             64
  148. 116     029eeef70580     7ff8065eec08            112
  149. 117     029eeef705f0     7ff8065eec08             38
  150. 118     029eeef70618     7ff8065eec08             90
  151. 119     029eeef70678     7ff8065eec08             42
  152. 120     029eeef706a8     7ff8065eec08            104
  153. 121     029eeef70710     7ff8065eec08            130
  154. 122     029eeef70798     7ff8065eec08            160
  155. 123     029eeef70838     7ff8065eec08            124
  156. 124     029eeef708b8     7ff8065eec08             38
  157. 125     029eeef708e0     7ff8065eec08             24
  158. 126     029eeef708f8     7ff8065eec08             44
  159. 127     029eeef70928     7ff8065eec08             24
  160. 128     029eeef70940     7ff8066e9ff8             24
  161. 129     029eeef70958     7ff8065eec08             26
  162. 130     029eeef70978     7ff8065eec08             42
  163. 131     029eeef709a8     7ff8065eec08             40
  164. 132     029eeef709d0     7ff8065eec08             32
  165. 133     029eeef709f0     7ff8065eec08             32
  166. 134     029eeef70a10     7ff8065eec08             40
  167. 135     029eeef70a38     7ff8065eec08             34
  168. 136     029eeef70a60     7ff8066bdfe0             40
  169. 137
  170. 138 Statistics:
  171. 139           MT Count TotalSize Class Name
  172. 140 7ff80668ad28     1        24 System.Collections.Generic.GenericEqualityComparer<System.String>
  173. 141 7ff80668c7d0     1        24 System.OrdinalCaseSensitiveComparer
  174. 142 7ff80668c108     1        24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer
  175. 143 7ff80668ca50     1        24 System.OrdinalIgnoreCaseComparer
  176. 144 7ff8066e96e8     1        24 System.IO.Stream+NullStream
  177. 145 7ff8066ee1f8     1        24 System.Threading.Tasks.Task+<>c
  178. 146 7ff8066e9ff8     1        24 System.Byte[]
  179. 147 7ff8066b3020     1        32 System.Diagnostics.Tracing.ActivityTracker
  180. 148 7ff8066b62e8     1        32 System.Collections.Generic.List<System.WeakReference<System.Diagnostics.Tracing.EventSource>>
  181. 149 7ff8066b1800     1        32 System.Guid
  182. 150 7ff8066b71c8     1        40 System.WeakReference<System.Diagnostics.Tracing.EventSource>[]
  183. 151 7ff8066ecea0     1        40 System.Threading.Tasks.TaskFactory
  184. 152 7ff8066ee618     1        40 System.IO.TextWriter+NullTextWriter
  185. 153 7ff80653a318     1        40 System.RuntimeType
  186. 154 7ff8066bdfe0     1        40 Interop+INPUT_RECORD
  187. 155 025e588f79b0     2        48 Free
  188. 156 7ff80668bfc8     2        48 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalComparer
  189. 157 7ff8066b2320     2        48 System.Diagnostics.Tracing.TraceLoggingEventHandleTable
  190. 158 7ff8066b56e0     2        48 System.WeakReference<System.Diagnostics.Tracing.EventSource>
  191. 159 7ff8066e0278     1        48 System.Reflection.RuntimeAssembly
  192. 160 7ff8066e1e90     1        48 System.Text.UTF8Encoding+UTF8EncodingSealed
  193. 161 7ff8066e24a8     2        48 System.Text.EncoderReplacementFallback
  194. 162 7ff8066e2220     2        48 System.Text.DecoderReplacementFallback
  195. 163 7ff8066e31c8     1        48 System.ConsolePal+WindowsConsoleStream
  196. 164 7ff8067013b0     1        48 System.Text.OSEncoder
  197. 165 7ff806703530     1        48 System.IO.TextWriter+SyncTextWriter
  198. 166 7ff80668fa90     2        56 System.String[]
  199. 167 7ff8066e0c28     1        64 System.Text.OSEncoding
  200. 168 7ff8066ec008     1        64 System.Threading.ContextCallback
  201. 169 7ff8066eddf0     1        72 System.Threading.Tasks.Task<System.Threading.Tasks.VoidTaskResult>
  202. 170 7ff8066847c8     1        80 System.Collections.Generic.Dictionary<System.String, System.Object>
  203. 171 7ff806535fa8     4        96 System.Object
  204. 172 7ff8066b3ce8     4        96 System.WeakReference<System.Diagnostics.Tracing.EventProvider>
  205. 173 7ff8066e9218     1       104 System.IO.StreamWriter
  206. 174 7ff806680a90     1       128 System.OutOfMemoryException
  207. 175 7ff806680b90     1       128 System.StackOverflowException
  208. 176 7ff806680c90     1       128 System.ExecutionEngineException
  209. 177 7ff8066b37a0     2       128 System.Diagnostics.Tracing.EventPipeEventProvider
  210. 178 7ff8066b3a08     2       176 System.Diagnostics.Tracing.EtwEventProvider
  211. 179 7ff8066b85b8     1       184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  212. 180 7ff8066b23f8     2       208 System.IntPtr[]
  213. 181 7ff8066b2b10     4       256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  214. 182 7ff806688ef8     1       288 System.Collections.Generic.Dictionary<System.String, System.Object>+Entry[]
  215. 183 7ff8066b21f0     1       400 System.Diagnostics.Tracing.RuntimeEventSource
  216. 184 7ff8066ee958     2       564 System.Char[]
  217. 185 7ff8065e9df8     3     3,284 System.Int32[]
  218. 186 7ff80653c4d8     2    16,368 System.Object[]
  219. 187 7ff8065eec08    64    35,132 System.String
  220. 188 Total 134 objects, 58,996 bytes
复制代码
                我们执行该命令,没有任何输出,因为在当前的托管堆中没有分配该类型的对象。我们【g】继续执行调试器,直到我们的控制台程序输出“Press any key to Exit”时,再次点击【break】按钮,中断调试器的执行,再次执行【!DumpHeap -type ExampleCore_5_1.Name】命令。
  1.   1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes.
  34.   2          Address               MT           Size
  35.   3     025e5a800028     7ff80653c4d8          8,184
  36.   4     025e5a802020     7ff80653c4d8          8,184
  37.   5     025e5d000028     7ff8065e9df8             96
  38.   6     025e5d000088     7ff806680a90            128
  39.   7     025e5d000108     7ff806680b90            128
  40.   8     025e5d000188     7ff806680c90            128
  41.   9     025e5d000208     7ff806535fa8             24
  42. 10     025e5d000220     7ff8066847c8             80
  43. 11     025e5d000270     7ff8065e9df8             68
  44. 12     025e5d0002b8     7ff806688ef8            288
  45. 13     025e5d0003d8     025e588f79b0             24 Free
  46. 14     025e5d0003f0     7ff8065e9df8          3,120
  47. 15     025e5d001020     7ff80668ad28             24
  48. 16     025e5d001038     7ff80668bfc8             24
  49. 17     025e5d001050     7ff80668bfc8             24
  50. 18     025e5d001068     7ff80668c7d0             24
  51. 19     025e5d001080     7ff80668c108             24
  52. 20     025e5d001098     7ff80668ca50             24
  53. 21     025e5d0010b0     7ff8065eec08             46
  54. 22     025e5d0010e0     7ff8065eec08            202
  55. 23     025e5d0011b0     7ff8065eec08             76
  56. 24     025e5d001200     025e588f79b0             24 Free
  57. 25     025e5d001218     7ff8065eec08         30,224
  58. 26     025e5d008828     7ff8065eec08             80
  59. 27     025e5d008878     7ff8065eec08            142
  60. 28     025e5d008908     7ff8065eec08             68
  61. 29     025e5d008950     7ff8065eec08             74
  62. 30     025e5d0089a0     7ff8065eec08            232
  63. 31     025e5d008a88     7ff8065eec08             66
  64. 32     025e5d008ad0     7ff8065eec08            468
  65. 33     025e5d008ca8     7ff8065eec08             60
  66. 34     025e5d008ce8     7ff8065eec08             58
  67. 35     025e5d008d28     7ff8065eec08             36
  68. 36     025e5d008d50     7ff8065eec08            160
  69. 37     025e5d008df0     7ff8065eec08             32
  70. 38     025e5d008e10     7ff8065eec08             64
  71. 39     025e5d008e50     7ff8065eec08             48
  72. 40     025e5d008e80     7ff80668fa90             32
  73. 41     025e5d008ea0     7ff80668fa90             24
  74. 42     025e5d008eb8     7ff8065eec08            274
  75. 43     025e5d008fd0     7ff8066b21f0            400
  76. 44     025e5d009160     7ff8066b2320             24
  77. 45     025e5d009178     7ff8066b23f8            104
  78. 46     025e5d0091e0     7ff8066b3020             32
  79. 47     025e5d009200     7ff8066b2b10             64
  80. 48     025e5d009240     7ff8066b3a08             88
  81. 49     025e5d009298     7ff8066b3ce8             24
  82. 50     025e5d0092b0     7ff8066b2b10             64
  83. 51     025e5d0092f0     7ff8066b37a0             64
  84. 52     025e5d009330     7ff8066b3ce8             24
  85. 53     025e5d009348     7ff8066b62e8             32
  86. 54     025e5d009368     7ff8066b71c8             40
  87. 55     025e5d009390     7ff8066b85b8            184
  88. 56     025e5d009448     7ff8066b2320             24
  89. 57     025e5d009460     7ff8066b23f8            104
  90. 58     025e5d0094c8     7ff8066b2b10             64
  91. 59     025e5d009508     7ff8066b3a08             88
  92. 60     025e5d009560     7ff8066b3ce8             24
  93. 61     025e5d009578     7ff8066b2b10             64
  94. 62     025e5d0095b8     7ff8066b37a0             64
  95. 63     025e5d0095f8     7ff8066b3ce8             24
  96. 64     025e5d009610     7ff8066b56e0             24
  97. 65     025e5d009628     7ff8066b56e0             24
  98. 66     025e5d009640     7ff806535fa8             24
  99. 67     025e5d009658     7ff8065eec08             46
  100. 68     025e5d009688     7ff8066e0278             48
  101. 69     025e5d0096b8     7ff8066e1e90             48
  102. 70     025e5d0096e8     7ff8066e24a8             24
  103. 71     025e5d009700     7ff8066e2220             24
  104. 72     025e5d009718     7ff8066e0c28             64
  105. 73     025e5d009758     7ff8066e24a8             24
  106. 74     025e5d009770     7ff8066e2220             24
  107. 75     025e5d009788     7ff8065eec08             46
  108. 76     025e5d0097b8     7ff8065eec08             46
  109. 77     025e5d0097e8     7ff8066e31c8             48
  110. 78     025e5d009818     7ff8065eec08             46
  111. 79     025e5d009848     7ff8066e96e8             24
  112. 80     025e5d009860     7ff8066e9218            104
  113. 81     025e5d0098c8     7ff806535fa8             24
  114. 82     025e5d0098e0     7ff8066ecea0             40
  115. 83     025e5d009908     7ff8066eddf0             72
  116. 84     025e5d009950     7ff8066ec008             64
  117. 85     025e5d009990     7ff8066ee1f8             24
  118. 86     025e5d0099a8     7ff8066ee618             40
  119. 87     025e5d0099d0     7ff8066ee958             28
  120. 88     025e5d0099f0     7ff8067013b0             48
  121. 89     025e5d009a20     7ff8066ee958            536
  122. 90     025e5d009c38     7ff806703530             48
  123. 91     025e5d009c68     7ff8065eec08             46
  124. 92     025e5d009c98     7ff806535fa8             24
  125. 93     025e5d009cb0     7ff8065eec08             46
  126. 94     029eeef70008     7ff8065eec08             24
  127. 95     029eeef70020     7ff80653a318             40
  128. 96     029eeef70048     7ff8065eec08            150
  129. 97     029eeef700e0     7ff8065eec08            122
  130. 98     029eeef70160     7ff8065eec08             42
  131. 99     029eeef70190     7ff8065eec08             30
  132. 100     029eeef701b0     7ff8065eec08             50
  133. 101     029eeef701e8     7ff8065eec08             38
  134. 102     029eeef70210     7ff8065eec08             26
  135. 103     029eeef70230     7ff8065eec08             34
  136. 104     029eeef70258     7ff8065eec08            118
  137. 105     029eeef702d0     7ff8065eec08            126
  138. 106     029eeef70350     7ff8066b1800             32
  139. 107     029eeef70370     7ff8065eec08             30
  140. 108     029eeef70390     7ff8065eec08             32
  141. 109     029eeef703b0     7ff8065eec08             84
  142. 110     029eeef70408     7ff8065eec08             98
  143. 111     029eeef70470     7ff8065eec08             48
  144. 112     029eeef704a0     7ff8065eec08             86
  145. 113     029eeef704f8     7ff8065eec08             32
  146. 114     029eeef70518     7ff8065eec08             36
  147. 115     029eeef70540     7ff8065eec08             64
  148. 116     029eeef70580     7ff8065eec08            112
  149. 117     029eeef705f0     7ff8065eec08             38
  150. 118     029eeef70618     7ff8065eec08             90
  151. 119     029eeef70678     7ff8065eec08             42
  152. 120     029eeef706a8     7ff8065eec08            104
  153. 121     029eeef70710     7ff8065eec08            130
  154. 122     029eeef70798     7ff8065eec08            160
  155. 123     029eeef70838     7ff8065eec08            124
  156. 124     029eeef708b8     7ff8065eec08             38
  157. 125     029eeef708e0     7ff8065eec08             24
  158. 126     029eeef708f8     7ff8065eec08             44
  159. 127     029eeef70928     7ff8065eec08             24
  160. 128     029eeef70940     7ff8066e9ff8             24
  161. 129     029eeef70958     7ff8065eec08             26
  162. 130     029eeef70978     7ff8065eec08             42
  163. 131     029eeef709a8     7ff8065eec08             40
  164. 132     029eeef709d0     7ff8065eec08             32
  165. 133     029eeef709f0     7ff8065eec08             32
  166. 134     029eeef70a10     7ff8065eec08             40
  167. 135     029eeef70a38     7ff8065eec08             34
  168. 136     029eeef70a60     7ff8066bdfe0             40
  169. 137
  170. 138 Statistics:
  171. 139           MT Count TotalSize Class Name
  172. 140 7ff80668ad28     1        24 System.Collections.Generic.GenericEqualityComparer<System.String>
  173. 141 7ff80668c7d0     1        24 System.OrdinalCaseSensitiveComparer
  174. 142 7ff80668c108     1        24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer
  175. 143 7ff80668ca50     1        24 System.OrdinalIgnoreCaseComparer
  176. 144 7ff8066e96e8     1        24 System.IO.Stream+NullStream
  177. 145 7ff8066ee1f8     1        24 System.Threading.Tasks.Task+<>c
  178. 146 7ff8066e9ff8     1        24 System.Byte[]
  179. 147 7ff8066b3020     1        32 System.Diagnostics.Tracing.ActivityTracker
  180. 148 7ff8066b62e8     1        32 System.Collections.Generic.List<System.WeakReference<System.Diagnostics.Tracing.EventSource>>
  181. 149 7ff8066b1800     1        32 System.Guid
  182. 150 7ff8066b71c8     1        40 System.WeakReference<System.Diagnostics.Tracing.EventSource>[]
  183. 151 7ff8066ecea0     1        40 System.Threading.Tasks.TaskFactory
  184. 152 7ff8066ee618     1        40 System.IO.TextWriter+NullTextWriter
  185. 153 7ff80653a318     1        40 System.RuntimeType
  186. 154 7ff8066bdfe0     1        40 Interop+INPUT_RECORD
  187. 155 025e588f79b0     2        48 Free
  188. 156 7ff80668bfc8     2        48 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalComparer
  189. 157 7ff8066b2320     2        48 System.Diagnostics.Tracing.TraceLoggingEventHandleTable
  190. 158 7ff8066b56e0     2        48 System.WeakReference<System.Diagnostics.Tracing.EventSource>
  191. 159 7ff8066e0278     1        48 System.Reflection.RuntimeAssembly
  192. 160 7ff8066e1e90     1        48 System.Text.UTF8Encoding+UTF8EncodingSealed
  193. 161 7ff8066e24a8     2        48 System.Text.EncoderReplacementFallback
  194. 162 7ff8066e2220     2        48 System.Text.DecoderReplacementFallback
  195. 163 7ff8066e31c8     1        48 System.ConsolePal+WindowsConsoleStream
  196. 164 7ff8067013b0     1        48 System.Text.OSEncoder
  197. 165 7ff806703530     1        48 System.IO.TextWriter+SyncTextWriter
  198. 166 7ff80668fa90     2        56 System.String[]
  199. 167 7ff8066e0c28     1        64 System.Text.OSEncoding
  200. 168 7ff8066ec008     1        64 System.Threading.ContextCallback
  201. 169 7ff8066eddf0     1        72 System.Threading.Tasks.Task<System.Threading.Tasks.VoidTaskResult>
  202. 170 7ff8066847c8     1        80 System.Collections.Generic.Dictionary<System.String, System.Object>
  203. 171 7ff806535fa8     4        96 System.Object
  204. 172 7ff8066b3ce8     4        96 System.WeakReference<System.Diagnostics.Tracing.EventProvider>
  205. 173 7ff8066e9218     1       104 System.IO.StreamWriter
  206. 174 7ff806680a90     1       128 System.OutOfMemoryException
  207. 175 7ff806680b90     1       128 System.StackOverflowException
  208. 176 7ff806680c90     1       128 System.ExecutionEngineException
  209. 177 7ff8066b37a0     2       128 System.Diagnostics.Tracing.EventPipeEventProvider
  210. 178 7ff8066b3a08     2       176 System.Diagnostics.Tracing.EtwEventProvider
  211. 179 7ff8066b85b8     1       184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  212. 180 7ff8066b23f8     2       208 System.IntPtr[]
  213. 181 7ff8066b2b10     4       256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  214. 182 7ff806688ef8     1       288 System.Collections.Generic.Dictionary<System.String, System.Object>+Entry[]
  215. 183 7ff8066b21f0     1       400 System.Diagnostics.Tracing.RuntimeEventSource
  216. 184 7ff8066ee958     2       564 System.Char[]
  217. 185 7ff8065e9df8     3     3,284 System.Int32[]
  218. 186 7ff80653c4d8     2    16,368 System.Object[]
  219. 187 7ff8065eec08    64    35,132 System.String
  220. 188 Total 134 objects, 58,996 bytes2          Address               MT           Size3     025e5d009ce0     7ff8066b9418             32 4 5 Statistics:6           MT Count TotalSize Class Name7 7ff8066b9418     1        32 ExampleCore_5_1.Name8 Total 1 objects, 32 bytes
复制代码
                有了输出内容了。这个结果和【!DumpHeap】命令的默认输出是一致的。首先给出这实例的特定数据(地址、方法表和大小),然后是统计信息,指出在托管堆中只有一个这种类型的实例。

    3.2、垃圾收集器内部工作机制
        CLR 的 GC 是一个高效的、可伸缩的以及可靠的自动内存管理器。在设计和实现 GC 之前,是遵循一些假设的。
        I、如果没有特殊声明,所有对象都是垃圾。这意味着,除非特别声明,否则 GC 会收集托管堆上所有的对象。从本质来看,它为系统中所有活跃的对象都实现了一种引用跟踪的模式,如果一个对象没有任何引用,就可以认为是垃圾,就可以被回收。
        II、假设托管堆上的所有对象的活跃时间都是很短暂的。这种假设基于:如果一个对象活跃了一段时间了,那么它很可能在更长一段时间内也是活跃的,因此不需要再次收集这个对象。
        III、通过代的概念跟踪对象的持续时间。活跃时间短的对象归为 0 代,而活跃时间更长的对象则归为第 1 代和第 2 代。对象的活跃时间增长,其相应的代也会递增。
        基于以上,我们可以得出一个定义:GC 是一个基于引用跟踪的垃圾收集器。

        3.2.1、代
            A、基础知识
                CLR GC 定义了 3 个级别的代,分别是:0 代、1代、2代。一个对象可以从某一代移到下一代,并且每个代的回收频率也是不一样的,0 代回收的最频繁,2代回收的最少。我们最新创建的对象,一般都会保存到 0 代。
                我们先上一个图,说一下 GC 垃圾回收算法是怎么回事。
                

                    


                每代都有预定义的空间容量。当新的内存分配请求到来的时候,并且第 0 代已无法再容纳新的对象时,也就是超过了第 0 代预定义的空间容量,就会启动 GC,执行垃圾回收的操作 。GC 就会回收掉没有任何根引用的对象(也就是垃圾对象),并且将所有带有根引用的对象升级到第 1 代。如果将第 0 代保留下来的对象提升到第 1 代时,超过了第 1 代预定空间容量,那么 GC 将在第 1 代回收没有根引用的对象,并将有根引用的对象升级到第 2 代。如果将对象从第 1 代升级到第 2 代,导致第 2 代的预定空间容量不足,此时 CLR 堆管理器就会尝试分配另一个内存段来容纳第 2 代中的对象。如果在创建新的内存段失败了,就会抛出一个 OutOfMemoryException 异常。
                如果内存段不再使用,CLR 堆管理器将释放它们。
                如果我们想理解对象具体在哪个代,那我们必须理解托管堆的内存段和代之间的关系。每个托管堆都包含了一个或者多个内存段用来容纳对象。而且,在这些内存段中有一部分空间是专门用来存储指定的代。来一张图说明一下托管堆的内存段是怎么回事。
                

                在这张图中,托管堆的内存段被划分为 3 个部分,分别存放不同代的对象,其中每个部分都有自己的起始地址,这个地址由 CLR 堆管理器来管理。第 0 代和第 1 代属于同一个内存段,这个内存段被称为临时内存段(ephemeral segment),它保存短暂活跃的对象。
                由于 GC 假设大多数对象都是短暂活跃的,因此GC 认为大多数对象的活跃时间都不会超过第 0 代,最多不超过第 1 代。位于第 2 代的对象是存活时间最长的对象,他们被收集的频率也会最低。当然,第 2 代对象也有可能保存在临时内存段中。通过查看对象的地址和了解存放每代对象的地址范围,我们就会很容易找到指定对象属于哪一代。
                如果我们想查看代的信息,可以使用 【!eeheap】命令,这个命令可以输出与 GC 和加载器相关的全部信息,如果我们只是想输出 GC 的信息,可以使用【!eeheap -gc】命令。

                注意1:由于我们是 .NET 8.0 的环境,不能使用 SOSEX 扩展里面的命令,如果是 .NET Framework ,我们就可以使用【!dumpgen】命令查看和代有关的对象,特别方便。【!dumpgen 0】表示查看第 0 代的所有对象,以此类推。
                注意2:GC.Collect()作用是什么?
                GC.Collect()本身所实现的功能比其字面意思表示的功能要多得多。它能强制触发一次垃圾回收的操作,而不管实际上是否需要垃圾收集。这句话的后半部分很重要,“。。。而不管实际上是否需要垃圾收集”。在应用程序执行期间,GC 可以不断的自我调节,以确保在应用程序的环境中表现出最优的行为。然而,通过 GC.Collect() 强制执行垃圾收集,有可能会破坏 GC 的自我微调算法。因此,在通常情况下,我们强烈建议不使用这个 API。

            B、眼见为实
                调试源码:ExampleCore_5_2
                调试任务:证明 GC 通过代管理对象
                1)、NTSD 调试
                    编译项目,打开【Visual Studio 2022 Developer Command Prompt v17.9.4】命令行工具,输入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_2\bin\Debug\net8.0\ExampleCore_5_2.exe】,打开【NTSD】调试器。
                    我们直接【g】运行调试器,直到调试器输出“Press any key to invoke GC”内容,如图:
                    

                    我们按【ctrl+c】组合键,进入中断模式。由于是我们主动中断的,在执行相关栈操作,必须先切换到托管主线程。
  1. 1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes. -type ExampleCore_5_1.Name
  34. 2          Address               MT           Size
  35. 3     025e5d009ce0     7ff8066b9418             32
  36. 4
  37. 5 Statistics:
  38. 6           MT Count TotalSize Class Name
  39. 7 7ff8066b9418     1        32 ExampleCore_5_1.Name
  40. 8 Total 1 objects, 32 bytes
复制代码
                    我们使用【!ClrStack -a】命令查看托管线程的调用栈,并显示局部变量和参数。
  1. 1 0:003> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007fff`cc08d0c4 c3              ret
  4. 4 0:000>
复制代码
                    这两个对象在托管堆上的地址分别是 0x00000238e5409640 和 0x00000238e5409660,这两个地址,我们可以使用【!DumpObj】或者【!do】命令,后跟对象的地址,就可以查看它们的详情。
  1. 1 0:000> !ClrStack -a
  2. 2 OS Thread Id: 0x3928 (0)
  3. 3         Child SP               IP Call Site
  4. 4 000000511E3FE448 00007fffcc08d0c4 [InlinedCallFrame: 000000511e3fe448]
  5. 5 000000511E3FE448 00007fffb093787a [InlinedCallFrame: 000000511e3fe448]
  6. 6 000000511E3FE420 00007FFFB093787A Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef)
  7. 7     PARAMETERS:
  8. 8         hConsoleInput = <no data>
  9. 9         buffer = <no data>
  10. 10         numInputRecords_UseOne = <no data>
  11. 11         numEventsRead = <no data>
  12. 12     LOCALS:
  13. 13         <no data>
  14. 14         <no data>
  15. 15         <no data>
  16. 16         <no data>
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20
  21. 21 000000511E3FE510 00007FFFB093AA0A System.ConsolePal.ReadKey(Boolean)
  22. 22     PARAMETERS:
  23. 23         intercept (<CLR reg>) = 0x0000000000000000
  24. 24     LOCALS:
  25. 25         <no data>
  26. 26         <no data>
  27. 27         <no data>
  28. 28         <no data>
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         0x000000511E3FE550 = 0x00000238e5409cd8
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         <no data>
  37. 37         <no data>
  38. 38
  39. 39 000000511E3FE5D0 00007FFEB11719F9 ExampleCore_5_2.Program.Main(System.String[])
  40. 40 <strong>    PARAMETERS:(表示是 Main() 方法的参数)
  41. </strong>41         args (0x000000511E3FE650) = 0x00000238e5408ea0
  42. 42 <strong>    LOCALS:(以下内容表示 Main() 方法的局部变量)
  43. </strong>43         <strong>0x000000511E3FE638 = 0x00000238e5409640</strong>
  44. 44         <strong>0x000000511E3FE630</strong> = <strong>0x00000238e5409660</strong>
  45. 45
  46. 46 0:000>
复制代码
                    有了对象的地址,我们再使用【!eeheap -gc】命令,查看 GC 的详情,包含每个代具体的信息,包括每个代的起始地址。
  1. 1 0:000> !DumpObj 0x00000238e5409640
  2. 2 Name:        ExampleCore_5_2.Name
  3. 3 MethodTable: 00007ffeb1229418
  4. 4 EEClass:     00007ffeb1231f18
  5. 5 Tracked Type: false
  6. 6 Size:        32(0x20) bytes
  7. 7 File:        E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_2\bin\Debug\net8.0\ExampleCore_5_2.dll
  8. 8 Fields:
  9. 9               MT    Field   Offset                 Type VT     Attr            Value Name
  10. 10 00007ffeb115ec08  4000001        8        System.String  0 instance 00000279775204a0 _first
  11. 11 00007ffeb115ec08  4000002       10        System.String  0 instance 00000279775204c0 _last
  12. 12
  13. 13 0:000> !do 0x00000238e5409660
  14. 14 Name:        ExampleCore_5_2.Name
  15. 15 MethodTable: 00007ffeb1229418
  16. 16 EEClass:     00007ffeb1231f18
  17. 17 Tracked Type: false
  18. 18 Size:        32(0x20) bytes
  19. 19 File:        E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_2\bin\Debug\net8.0\ExampleCore_5_2.dll
  20. 20 Fields:
  21. 21               MT    Field   Offset                 Type VT     Attr            Value Name
  22. 22 00007ffeb115ec08  4000001        8        System.String  0 instance 00000279775204e8 _first
  23. 23 00007ffeb115ec08  4000002       10        System.String  0 instance 00000279775204c0 _last
  24. 24 0:000>
复制代码
                    两个局部变量的地址分别是:0x00000238e5409640 和 0x00000238e5409660,有了对象的地址,我们再和每一代的起始地址进行比较,就可以得到答案。只需比较地址高位地址的前6-8位就可以。第 0 代地址前面部分都是 00000238E54 ,我们对象的地址也是以 00000238e54 开头的,其他的就可以不用看了,说明 n1 和 n2 都在第 0 代。
                    我们继续【g】运行调试器,直到调试器输出“Press any key to invoke GC”字样,如图:
                    

                    继续按组合键【ctrl+c】进入中断模式,此时,也需要切换到托管主线程。
  1. 1 0:000> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000238E5400028 <strong>(第 0 代)</strong>
  4. 4 generation 1 starts at 0x00000238E5000028 <strong>(第 1 代)</strong>
  5. 5 generation 2 starts at 0x0000027977520008 <strong>(第 2 代)</strong>
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:   <strong>(第 0 代起始地址)
  9. </strong> 9 00000278F6A1F320  <strong>00000238E5400028</strong>  00000238E5400028  00000238E5411000  0x0(0)  0x10fd8(69592)
  10. 10 generation 1:    <strong>(第 1 代起始地址)
  11. </strong>11 00000278F6A1F270  <strong>00000238E5000028</strong>  00000238E5000028  00000238E5001000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:     <strong>(第 2 代起始地址)
  13. </strong>13 00000238E0EEE240  <strong>0000027977520008</strong>  0000027977520AD8  0000027977530000  0xad0(2768)  0xfff8(65528)
  14. 14 00000278F6A1F1C0  00000238E4C00028  00000238E4C00028  00000238E4C01000  0x0(0)  0xfd8(4056)
  15. 15 Large object heap starts at 0x0000000000000000
  16. 16          segment             begin         allocated         committed    allocated size    committed size
  17. 17 00000278F6A1F3D0  00000238E5800028  00000238E5800028  00000238E5801000  0x0(0)  0xfd8(4056)
  18. 18 Pinned object heap starts at 0x0000000000000000
  19. 19 00000278F6A1EC40  00000238E2C00028  00000238E2C04018  00000238E2C11000  0x3ff0(16368)  0x10fd8(69592)
  20. 20 Total Allocated Size:              Size: 0x4ac0 (19136) bytes.
  21. 21 Total Committed Size:              Size: 0x23f58 (147288) bytes.
  22. 22 ------------------------------
  23. 23 GC Allocated Heap Size:    Size: 0x4ac0 (19136) bytes.
  24. 24 GC Committed Heap Size:    Size: 0x23f58 (147288) bytes.
复制代码
                    继续执行【!ClrStack -a】查看托管线程调用栈。
  1. 1 0:002> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007fff`cc08d0c4 c3              ret
  4. 4 0:000>
复制代码
                    我们继续使用【!eeheap -gc】命令查看一下 GC 的详情。
  1. 1 0:000> !ClrStack -a
  2. 2 OS Thread Id: 0x1c98 (0)
  3. 3         Child SP               IP Call Site
  4. 4 0000001CC517E4B8 00007fffcc08d0c4 [InlinedCallFrame: 0000001cc517e4b8]
  5. 5 0000001CC517E4B8 00007fffc0ff787a [InlinedCallFrame: 0000001cc517e4b8]
  6. 6 0000001CC517E490 00007FFFC0FF787A Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef)
  7. 7     PARAMETERS:
  8. 8         hConsoleInput = <no data>
  9. 9         buffer = <no data>
  10. 10         numInputRecords_UseOne = <no data>
  11. 11         numEventsRead = <no data>
  12. 12     LOCALS:
  13. 13         <no data>
  14. 14         <no data>
  15. 15         <no data>
  16. 16         <no data>
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20
  21. 21 0000001CC517E580 00007FFFC0FFAA0A System.ConsolePal.ReadKey(Boolean)
  22. 22     PARAMETERS:
  23. 23         intercept (<CLR reg>) = 0x0000000000000000
  24. 24     LOCALS:
  25. 25         <no data>
  26. 26         <no data>
  27. 27         <no data>
  28. 28         <no data>
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         0x0000001CC517E5C0 = 0x000001363cc09cd8
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         <no data>
  37. 37         <no data>
  38. 38
  39. 39 0000001CC517E640 00007FFEB6431A22 ExampleCore_5_2.Program.Main(System.String[])
  40. 40     PARAMETERS:
  41. 41         args (0x0000001CC517E6C0) = 0x000001363cc08ea0
  42. 42     LOCALS:
  43. 43         0x0000001CC517E6A8 = <strong>0x0000000000000000(n1 没有根引用,已经被回收了)</strong>
  44. 44         0x0000001CC517E6A0 = <strong>0x000001363cc09660(n2 有根引用,为被回收,但是它的代应该是提升到第 1 代了)</strong>
复制代码
                    我们已经执行了一次垃圾回收,代的起始地址也发生了变化。n1 地址变成了 0 ,表示被回收了,现在只有 n2 了,它的地址是:0x000001363cc09660,再次和每个代的起始地址比较吧,只是比较高位地址部分就可以了。n2 地址前缀是:000001363cc,第 1 代起始地址的前缀是:000001363CC,很明显,是一致的,其他的就可以不用看了,当然,看看理解更好点。现在 n2 在第 1 代了。
                    我们继续【g】,直到调试器输出“Press any key to Exit”字样,效果如图:
                    

                    我们继续按组合键【ctrl+c】进入到调试器的中断模式,再次切换到托管线程上下文中。
  1. 1 0:000> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x000001363C400028<strong>(第 0 代)</strong>
  4. 4 generation 1 starts at 0x000001363CC00028<strong>(第 1 代)</strong>
  5. 5 generation 2 starts at 0x00000176CEEC0008<strong>(第 2 代)</strong>
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:   <strong>(第 0 代起始地址)
  9. </strong> 9 000001764E2BF1C0  <strong>000001363C400028</strong>  000001363C400028  000001363C411000  0x0(0)  0x10fd8(69592)
  10. 10 generation 1:   <strong>(第 1 代起始地址)
  11. </strong>11 000001764E2BF320  <strong>000001363CC00028</strong>  000001363CC09CF0  000001363CC11000  0x9cc8(40136)  0x10fd8(69592)
  12. 12 generation 2:   <strong>(第 2 代起始地址)
  13. </strong>13 000001363885E240  <strong>00000176CEEC0008</strong>  00000176CEEC0AF8  00000176CEED0000  0xaf0(2800)  0xfff8(65528)
  14. 14 000001764E2BF950  000001363F000028  000001363F000028  000001363F001000  0x0(0)  0xfd8(4056)
  15. 15 Large object heap starts at 0x0000000000000000
  16. 16          segment             begin         allocated         committed    allocated size    committed size
  17. 17 000001764E2BF3D0  000001363D000028  000001363D000028  000001363D001000  0x0(0)  0xfd8(4056)
  18. 18 Pinned object heap starts at 0x0000000000000000
  19. 19 000001764E2BEC40  000001363A400028  000001363A404018  000001363A411000  0x3ff0(16368)  0x10fd8(69592)
  20. 20 Total Allocated Size:              Size: 0xe7a8 (59304) bytes.
  21. 21 Total Committed Size:              Size: 0x33f58 (212824) bytes.
  22. 22 ------------------------------
  23. 23 GC Allocated Heap Size:    Size: 0xe7a8 (59304) bytes.
  24. 24 GC Committed Heap Size:    Size: 0x33f58 (212824) bytes.
复制代码
                    使用【!clrstack -a】命令,查看一下托管线程的调用栈。
  1. 1 0:003> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007fff`cc08d0c4 c3              ret
复制代码
                    n2 对象在托管堆上的地址是:0x000001363cc09660,我们使用【!eeheap -gc】查看 GC 的详情。
  1. 1 0:000> !clrstack -a
  2. 2 OS Thread Id: 0x1c98 (0)
  3. 3         Child SP               IP Call Site
  4. 4 0000001CC517E4B8 00007fffcc08d0c4 [InlinedCallFrame: 0000001cc517e4b8]
  5. 5 0000001CC517E4B8 00007fffc0ff787a [InlinedCallFrame: 0000001cc517e4b8]
  6. 6 0000001CC517E490 00007FFFC0FF787A Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef)
  7. 7     PARAMETERS:
  8. 8         hConsoleInput = <no data>
  9. 9         buffer = <no data>
  10. 10         numInputRecords_UseOne = <no data>
  11. 11         numEventsRead = <no data>
  12. 12     LOCALS:
  13. 13         <no data>
  14. 14         <no data>
  15. 15         <no data>
  16. 16         <no data>
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20
  21. 21 0000001CC517E580 00007FFFC0FFAA0A System.ConsolePal.ReadKey(Boolean)
  22. 22     PARAMETERS:
  23. 23         intercept (<CLR reg>) = 0x0000000000000000
  24. 24     LOCALS:
  25. 25         <no data>
  26. 26         <no data>
  27. 27         <no data>
  28. 28         <no data>
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         0x0000001CC517E5C0 = 0x000001363cc09cd8
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         <no data>
  37. 37         <no data>
  38. 38
  39. 39 0000001CC517E640 00007FFEB6431A45 ExampleCore_5_2.Program.Main(System.String[])
  40. 40     PARAMETERS:
  41. 41         args (0x0000001CC517E6C0) = 0x000001363cc08ea0
  42. 42     LOCALS:
  43. 43         0x0000001CC517E6A8 = 0x0000000000000000
  44. 44         0x0000001CC517E6A0 = <strong>0x000001363cc09660</strong>
复制代码
                    n2 对象的地址:0x000001363cc09660,我们在第 2 代里,发现有2个内存段,第 2 个内存段的起始地址是:000001363CC00028,n2 对象的地址正好在第 2 代的第 2 个内存段的地址里。

                2)、Windbg Preview 调试
                    编译项目,打开【Windbg Preview】,依次点击【文件】---【Launch executable】,加载我们的项目文件:ExampleCore_5_2.exe,进入调试器。
                    进入到调试器,我们直接【g】运行调试器,直到我们的控制台程序输出“Press any key to invoke GC”字样。点击调试器的【break】按钮,中断调试器的执行。由于我们是手动中断,需要切换到托管线程的调用栈上,执行命令【~0s】。
  1. 1 0:000> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x000001363F000028<strong>(第 0 代 起始地址)</strong>
  4. 4 generation 1 starts at 0x000001363C400028<strong>(第 1 代 起始地址)</strong>
  5. 5 generation 2 starts at 0x00000176CEEC0008<strong>(第 2 代 起始地址)</strong>
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:<strong>(第 0 代)
  9. </strong> 9 000001764E2BF950  <strong>000001363F000028</strong>  000001363F000028  000001363F011000  0x0(0)  0x10fd8(69592)
  10. 10 generation 1:<strong>(第 1 代)
  11. </strong>11 000001764E2BF1C0  <strong>000001363C400028</strong>  000001363C400028  000001363C411000  0x0(0)  0x10fd8(69592)
  12. 12 generation 2:<strong>(第 2 代)
  13. </strong>13 000001363885E240  <strong>00000176CEEC0008</strong>  00000176CEEC0AF8  00000176CEED0000  0xaf0(2800)  0xfff8(65528)
  14. 14 000001764E2BF320  <strong>000001363CC00028</strong>  000001363CC09CF0  000001363CC11000  0x9cc8(40136)  0x10fd8(69592)
  15. 15 Large object heap starts at 0x0000000000000000
  16. 16          segment             begin         allocated         committed    allocated size    committed size
  17. 17 000001764E2BF3D0  000001363D000028  000001363D000028  000001363D001000  0x0(0)  0xfd8(4056)
  18. 18 Pinned object heap starts at 0x0000000000000000
  19. 19 000001764E2BEC40  000001363A400028  000001363A404018  000001363A411000  0x3ff0(16368)  0x10fd8(69592)
  20. 20 Total Allocated Size:              Size: 0xe7a8 (59304) bytes.
  21. 21 Total Committed Size:              Size: 0x43f58 (278360) bytes.
  22. 22 ------------------------------
  23. 23 GC Allocated Heap Size:    Size: 0xe7a8 (59304) bytes.
  24. 24 GC Committed Heap Size:    Size: 0x43f58 (278360) bytes.
复制代码
                    继续使用【!clrstack -a】命令,查看托管线程栈的调用栈,打印出所有参数和局部变量。
  1. 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ff9`401cd0c4 c3              ret
复制代码
                    红色标注的两项就是我们的局部变量,分别是:n1 和 n2。接下来,我们就看看这两个变量属于哪一代。
                    继续执行【!eeheap -gc】命令。
  1. 1 0:000> !ClrStack -a
  2. 2 OS Thread Id: 0x505c (0)
  3. 3         Child SP               IP Call Site
  4. 4 0000005C5277E668 00007ff9401cd0c4 [InlinedCallFrame: 0000005c5277e668]
  5. 5 0000005C5277E668 00007ff87a4d787a [InlinedCallFrame: 0000005c5277e668]
  6. 6 0000005C5277E640 00007ff87a4d787a Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  7. 7     PARAMETERS:
  8. 8         hConsoleInput = <no data>
  9. 9         buffer = <no data>
  10. 10         numInputRecords_UseOne = <no data>
  11. 11         numEventsRead = <no data>
  12. 12     LOCALS:
  13. 13         <no data>
  14. 14         <no data>
  15. 15         <no data>
  16. 16         <no data>
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20
  21. 21 0000005C5277E730 00007ff87a4daa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  22. 22     PARAMETERS:
  23. 23         intercept (<CLR reg>) = 0x0000000000000000
  24. 24     LOCALS:
  25. 25         <no data>
  26. 26         <no data>
  27. 27         <no data>
  28. 28         <no data>
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         0x0000005C5277E770 = 0x000001eaf1009cd8
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         <no data>
  37. 37         <no data>
  38. 38
  39. 39 0000005C5277E7F0 00007ff7fcab19f9 ExampleCore_5_2.Program.Main(System.String[]) [E:\Visual Studio\...\ExampleCore_5_2\Program.cs @ 29]
  40. 40 <strong>    PARAMETERS:</strong>(表示Main方法的参数,是一个数组)
  41. 41         args (0x0000005C5277E870) = 0x000001eaf1008ea0
  42. 42 <strong>    LOCALS</strong>:(表示是局部变量)
  43. 43         0x0000005C5277E858 = <strong>0x000001eaf1009640</strong>
  44. 44         0x0000005C5277E850 = <strong>0x000001eaf1009660</strong>
复制代码
                    两个局部变量的地址分别是:0x000001eaf1009640 和 0x000001eaf1009660,第 0 代起始地址是 01eaf1000028,两个局部变量前8位都是一致的(看红色部分),用这个地址和每个代的开始地址比较很容易知道属于第 0 代。
                    我们继续【g】运行调试器,直到我们的控制台程序输出第二个“Press any key to invoke GC”字样,点击调试器【break】按钮,中断调试器的执行,又因为是我们手动中断,需要切换到托管线程上,执行命令【~0s】。
  1. 1 0:000> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x000001363F000028<strong>(第 0 代 起始地址)</strong>
  4. 4 generation 1 starts at 0x000001363C400028<strong>(第 1 代 起始地址)</strong>
  5. 5 generation 2 starts at 0x00000176CEEC0008<strong>(第 2 代 起始地址)</strong>
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:<strong>(第 0 代)
  9. </strong> 9 000001764E2BF950  <strong>000001363F000028</strong>  000001363F000028  000001363F011000  0x0(0)  0x10fd8(69592)
  10. 10 generation 1:<strong>(第 1 代)
  11. </strong>11 000001764E2BF1C0  <strong>000001363C400028</strong>  000001363C400028  000001363C411000  0x0(0)  0x10fd8(69592)
  12. 12 generation 2:<strong>(第 2 代)
  13. </strong>13 000001363885E240  <strong>00000176CEEC0008</strong>  00000176CEEC0AF8  00000176CEED0000  0xaf0(2800)  0xfff8(65528)
  14. 14 000001764E2BF320  <strong>000001363CC00028</strong>  000001363CC09CF0  000001363CC11000  0x9cc8(40136)  0x10fd8(69592)
  15. 15 Large object heap starts at 0x0000000000000000
  16. 16          segment             begin         allocated         committed    allocated size    committed size
  17. 17 000001764E2BF3D0  000001363D000028  000001363D000028  000001363D001000  0x0(0)  0xfd8(4056)
  18. 18 Pinned object heap starts at 0x0000000000000000
  19. 19 000001764E2BEC40  000001363A400028  000001363A404018  000001363A411000  0x3ff0(16368)  0x10fd8(69592)
  20. 20 Total Allocated Size:              Size: 0xe7a8 (59304) bytes.
  21. 21 Total Committed Size:              Size: 0x43f58 (278360) bytes.
  22. 22 ------------------------------
  23. 23 GC Allocated Heap Size:    Size: 0xe7a8 (59304) bytes.
  24. 24 GC Committed Heap Size:    Size: 0x43f58 (278360) bytes.
复制代码
                    我们再次执行【!clrstack -a】命令,查看托管线程栈。
  1. 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ff9`401cd0c4 c3              ret
复制代码
                    这里的内容大部分都是相同的,红色标注的注意看,一个值变成了 0 ,说明被(n1 = null;GC.Collect())回收了。0x000001eaf1009660 这个值就是 n2,由于执行了垃圾会后,n2 没有被回收,肯定从第 0 代升级到第 1 代了,我们执行【!eeheap -gc】命令来验证。
  1. 1 0:000> !clrstack -a
  2. 2 OS Thread Id: 0x505c (0)
  3. 3         Child SP               IP Call Site
  4. 4 0000005C5277E668 00007ff9401cd0c4 [InlinedCallFrame: 0000005c5277e668]
  5. 5 0000005C5277E668 00007ff87a4d787a [InlinedCallFrame: 0000005c5277e668]
  6. 6 0000005C5277E640 00007ff87a4d787a Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  7. 7     PARAMETERS:
  8. 8         hConsoleInput = <no data>
  9. 9         buffer = <no data>
  10. 10         numInputRecords_UseOne = <no data>
  11. 11         numEventsRead = <no data>
  12. 12     LOCALS:
  13. 13         <no data>
  14. 14         <no data>
  15. 15         <no data>
  16. 16         <no data>
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20
  21. 21 0000005C5277E730 00007ff87a4daa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  22. 22     PARAMETERS:
  23. 23         intercept (<CLR reg>) = 0x0000000000000000
  24. 24     LOCALS:
  25. 25         <no data>
  26. 26         <no data>
  27. 27         <no data>
  28. 28         <no data>
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         0x0000005C5277E770 = 0x000001eaf1009cd8
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         <no data>
  37. 37         <no data>
  38. 38
  39. 39 0000005C5277E7F0 00007ff7fcab1a22 ExampleCore_5_2.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_2_1\Program.cs @ 35]
  40. 40     PARAMETERS:
  41. 41         args (0x0000005C5277E870) = 0x000001eaf1008ea0
  42. 42     LOCALS:
  43. 43         0x0000005C5277E858 = <strong>0x0000000000000000(这里变成0了,说明被回收了,也就是 n1 变量)</strong>
  44. 44         0x0000005C5277E850 = <strong>0x000001eaf1009660</strong>
复制代码
                  对象的地址是 0x000001eaf1009660,开始比较,第 0 代的开始地址:01eaf0800028,肯定不是,第 1 代的开始地址是:01eaf1000028,这个地址是符合的,也就是说 0x000001eaf1009660 这地址在 01eaf1000028 这地址里面的,证明了我们的说法。
                  我们继续【g】运行调试器,直到我们的控制台程序输出“Press any key to Exit”字样,点击调试器的【break】按钮,中断调试器的执行,我们还必须切换到托管线程上,执行命令【~0s】。
  1. 1 0:000> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x000001363F000028<strong>(第 0 代 起始地址)</strong>
  4. 4 generation 1 starts at 0x000001363C400028<strong>(第 1 代 起始地址)</strong>
  5. 5 generation 2 starts at 0x00000176CEEC0008<strong>(第 2 代 起始地址)</strong>
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:<strong>(第 0 代)
  9. </strong> 9 000001764E2BF950  <strong>000001363F000028</strong>  000001363F000028  000001363F011000  0x0(0)  0x10fd8(69592)
  10. 10 generation 1:<strong>(第 1 代)
  11. </strong>11 000001764E2BF1C0  <strong>000001363C400028</strong>  000001363C400028  000001363C411000  0x0(0)  0x10fd8(69592)
  12. 12 generation 2:<strong>(第 2 代)
  13. </strong>13 000001363885E240  <strong>00000176CEEC0008</strong>  00000176CEEC0AF8  00000176CEED0000  0xaf0(2800)  0xfff8(65528)
  14. 14 000001764E2BF320  <strong>000001363CC00028</strong>  000001363CC09CF0  000001363CC11000  0x9cc8(40136)  0x10fd8(69592)
  15. 15 Large object heap starts at 0x0000000000000000
  16. 16          segment             begin         allocated         committed    allocated size    committed size
  17. 17 000001764E2BF3D0  000001363D000028  000001363D000028  000001363D001000  0x0(0)  0xfd8(4056)
  18. 18 Pinned object heap starts at 0x0000000000000000
  19. 19 000001764E2BEC40  000001363A400028  000001363A404018  000001363A411000  0x3ff0(16368)  0x10fd8(69592)
  20. 20 Total Allocated Size:              Size: 0xe7a8 (59304) bytes.
  21. 21 Total Committed Size:              Size: 0x43f58 (278360) bytes.
  22. 22 ------------------------------
  23. 23 GC Allocated Heap Size:    Size: 0xe7a8 (59304) bytes.
  24. 24 GC Committed Heap Size:    Size: 0x43f58 (278360) bytes.
复制代码
                  再次执行【!clrstack -a】命令,查看托管线程栈。
  1. 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ff9`401cd0c4 c3              ret
复制代码
                  有了对象的地址,我们继续执行【!eeheap -gc】命令查看 GC 的详情。
  1. 1 0:000> !clrstack -a
  2. 2 OS Thread Id: 0x505c (0)
  3. 3         Child SP               IP Call Site
  4. 4 0000005C5277E668 00007ff9401cd0c4 [InlinedCallFrame: 0000005c5277e668]
  5. 5 0000005C5277E668 00007ff87a4d787a [InlinedCallFrame: 0000005c5277e668]
  6. 6 0000005C5277E640 00007ff87a4d787a Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  7. 7     PARAMETERS:
  8. 8         hConsoleInput = <no data>
  9. 9         buffer = <no data>
  10. 10         numInputRecords_UseOne = <no data>
  11. 11         numEventsRead = <no data>
  12. 12     LOCALS:
  13. 13         <no data>
  14. 14         <no data>
  15. 15         <no data>
  16. 16         <no data>
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20
  21. 21 0000005C5277E730 00007ff87a4daa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  22. 22     PARAMETERS:
  23. 23         intercept (<CLR reg>) = 0x0000000000000000
  24. 24     LOCALS:
  25. 25         <no data>
  26. 26         <no data>
  27. 27         <no data>
  28. 28         <no data>
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         0x0000005C5277E770 = 0x000001eaf1009cd8
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         <no data>
  37. 37         <no data>
  38. 38
  39. 39 0000005C5277E7F0 00007ff7fcab1a45 ExampleCore_5_2.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_2\Program.cs @ 40]
  40. 40     PARAMETERS:
  41. 41         args (0x0000005C5277E870) = 0x000001eaf1008ea0
  42. 42     LOCALS:
  43. 43         0x0000005C5277E858 = 0x0000000000000000
  44. 44         0x0000005C5277E850 = <strong>0x000001eaf1009660(这就是 n2 局部变量)</strong>
复制代码
                  对象的地址是:0x000001eaf1009660,第 0 代的开始地址是:01eaf3400028,比较前6-8位即可,不符合,第 1 代开始地址是:01eaf0800028,也不符合,第 2 代的开始地址:01eaf1000028,我们看到了,地址前8位是一样的,所以也就证明了我们的说法,n2 已经提升到第 2 代了。

        3.2.2、根对象
            A、基础知识
                C# 的引用跟踪回收算法,核心在于寻找【根对象】,凡是托管堆上的某个对象被【根对象】所引用,GC就不会回收这个对象的。
                GC 本身并不会监测哪些对象仍然被引用,而是使用 CLR 中其他了解对象生命周期的组件。
                通常3个地方有根对象。
                I、线程栈
                    方法作用域下的引用类型,自然就是根对象。
                II、终结器队列(Finalizer queues)
                    带有析构函数的对象自然会被加入到【终结器队列】中,终结线程会在对象成为垃圾对象后的某个时刻执行对象的析构函数。
                III、句柄表(handle table)
                    CLR 为每个应用程序域提供一组句柄表,在这些句柄表中包含了指向托管堆上固定引用类型的指针。换句话说,凡是被 Strong、Pinned 标记的对象都会被放入到【句柄表】中,比如:static 对象。句柄表就是在 CLR 私有堆中具有一个字典类型的数据结构,用于存储被 Strong、Pinned 标记的对象。
                    句柄类型是一种值类型,如果想转储出句柄的内容,只能使用【!DumpVC】,【!DumpObj】命令是针对引用类型的。
                IIII、即时编译器JIT
                    它负责将 IL 代码转换为机器码,因此它知道在任意时刻有哪些局部变量仍然被认为是活跃的。JIT 编译器将这些信息维护在一张表中,当 GC 要查询活跃对象的时候,会用到这张表。

            B、眼见为实
                调试源码:ExampleCore_5_3
                调试任务:使用【!gcroot】命令查找对象的根引用。
                1)、NTSD 调试
                    编译项目,打开【Visual Studio 2022 Developer Command Prompt v17.9.6】命令行工具,输入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\bin\Debug\net8.0\ExampleCore_5_3.exe】,打开【NTSD】调试器。
                    【g】直接运行调试器,直到调试器输出“Press any key to Exit”字样,效果如图:
                    

                    按组合键【ctrl+c】进入中断模式,然后切换到托管线程上下文。
  1. 1 0:000> !eeheap -gc
  2. 2
  3. 3 ========================================
  4. 4 Number of GC Heaps: 1
  5. 5 ----------------------------------------
  6. 6 Small object heap
  7. 7          segment            begin        allocated        committed allocated size  committed size
  8. 8 generation 0:
  9. 9     022b0269f950     01eaf3400028     01eaf3400028     01eaf3411000                 0x11000 (69632)
  10. 10 generation 1:
  11. 11     022b0269f1c0     01eaf0800028     01eaf0800028     01eaf0811000                 0x11000 (69632)
  12. 12 generation 2:
  13. 13     022b0269f320     01eaf1000028     01eaf1009cf0     01eaf1011000 0x9cc8 (40136)  0x11000 (69632)
  14. 14 NonGC heap
  15. 15          segment            begin        allocated        committed allocated size  committed size
  16. 16     01eaecb64230     022b832a0008     022b832a0af8     022b832b0000 0xaf0 (2800)    0x10000 (65536)
  17. 17 Large object heap
  18. 18          segment            begin        allocated        committed allocated size  committed size
  19. 19     022b0269f3d0     01eaf1400028     01eaf1400028     01eaf1401000                 0x1000 (4096)  
  20. 20 Pinned object heap
  21. 21          segment            begin        allocated        committed allocated size  committed size
  22. 22     022b0269ec40     01eaee800028     01eaee804018     01eaee811000 0x3ff0 (16368)  0x11000 (69632)
  23. 23 ------------------------------
  24. 24 GC Allocated Heap Size:    Size: 0xe7a8 (59304) bytes.
  25. 25 GC Committed Heap Size:    Size: 0x55000 (348160) bytes.
复制代码
                    继续使用【!clrstack -a】命令查看一下托管线程调用栈的情况。
  1. 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ff8`bec2d0c4 c3              ret
复制代码
                    我们可以使用【!do 0x0000014c5f809660】命令或者【!DumpObj 0x0000014c5f809660】命令验证一下是否正确。
  1. 1 0:000> !clrstack -a
  2. 2 OS Thread Id: 0x3a00 (0)
  3. 3         Child SP               IP Call Site
  4. 4 00000030723FE7A8 00007ff8bec2d0c4 [InlinedCallFrame: 00000030723fe7a8]
  5. 5 00000030723FE7A8 00007ff8b261787a [InlinedCallFrame: 00000030723fe7a8]
  6. 6 00000030723FE780 00007FF8B261787A Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef)
  7. 7     PARAMETERS:
  8. 8         hConsoleInput = <no data>
  9. 9         buffer = <no data>
  10. 10         numInputRecords_UseOne = <no data>
  11. 11         numEventsRead = <no data>
  12. 12     LOCALS:
  13. 13         <no data>
  14. 14         <no data>
  15. 15         <no data>
  16. 16         <no data>
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20
  21. 21 00000030723FE870 00007FF8B261AA0A System.ConsolePal.ReadKey(Boolean)
  22. 22     PARAMETERS:
  23. 23         intercept (<CLR reg>) = 0x0000000000000000
  24. 24     LOCALS:
  25. 25         <no data>
  26. 26         <no data>
  27. 27         <no data>
  28. 28         <no data>
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         0x00000030723FE8B0 = 0x0000014c5f809868
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         <no data>
  37. 37         <no data>
  38. 38
  39. 39 00000030723FE930 00007FF7AD521AF2 ExampleCore_5_3.Program.Run()
  40. 40     PARAMETERS:
  41. 41         this (0x00000030723FE990) = 0x0000014c5f809640
  42. 42     LOCALS:
  43. 43         0x00000030723FE978 = <strong>0x0000014c5f809660(Name 类型实例的地址)</strong>
  44. 44
  45. 45 00000030723FE990 00007FF7AD521988 ExampleCore_5_3.Program.Main(System.String[])
  46. 46     PARAMETERS:
  47. 47         args (0x00000030723FE9D0) = 0x0000014c5f808ea0
  48. 48     LOCALS:
  49. 49         0x00000030723FE9B8 = 0x0000014c5f809640
复制代码
                    我们有了对象的地址,就可以使用【!gcroot 0x0000014c5f809660】命令查看一下它的根引用。
  1. 1 0:000> !do 0x0000014c5f809660
  2. 2 Name:        ExampleCore_5_3.Name
  3. 3 MethodTable: 00007ff7ad5d94b0
  4. 4 EEClass:     00007ff7ad5e2068
  5. 5 Tracked Type: false
  6. 6 Size:        32(0x20) bytes
  7. 7 File:        E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\bin\Debug\net8.0\ExampleCore_5_3.dll
  8. 8 Fields:
  9. 9               MT    Field   Offset                 Type VT     Attr            Value Name
  10. 10 00007ff7ad50ec08  4000001        8        System.String  0 instance 0000018cf1b004e0 _first
  11. 11 00007ff7ad50ec08  4000002       10        System.String  0 instance 0000018cf1b00500 _last
复制代码
                     我们看到了 ExampleCore_5_3.Name 类型在 2个线程和一个句柄表中有引用。我们可以使用【!t】命令或者【!threads】命令查看托管所有线程。
  1. 1 0:000> !gcroot 0x0000014c5f809660
  2. 2 Thread 3a00:<strong>(OSID 3a00,是主线程)
  3. </strong> 3     00000030723FE930 00007FF7AD521AF2 ExampleCore_5_3.Program.Run() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\Program.cs @ 47]
  4. 4         rbp-8: 00000030723fe978
  5. 5             -><strong>  0000014C5F809660</strong> ExampleCore_5_3.Name
  6. 6
  7. 7 Thread 3170:<strong>(OSID 3170,是通过 Thread 启动的线程)
  8. </strong> 8     00000030731FF960 00007FF7AD521CCD ExampleCore_5_3.Program.Worker(System.Object) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\Program.cs @ 59]
  9. 9         rbp-8: 00000030731ff9a8
  10. 10             -><strong>  0000014C5F809660</strong> ExampleCore_5_3.Name
  11. 11
  12. 12     00000030731FF960 00007FF7AD521CCD ExampleCore_5_3.Program.Worker(System.Object) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\Program.cs @ 59]
  13. 13         rbp+18: 00000030731ff9c8
  14. 14             -><strong>  0000014C5F809660</strong> ExampleCore_5_3.Name
  15. 15
  16. 16 HandleTable:<strong>(句柄表)
  17. </strong>17     0000014C5B4113E8 (strong handle)
  18. 18     -> 0000014C5D000028 System.Object[]
  19. 19     -><strong> 0000014C5F809660</strong> ExampleCore_5_3.Name
  20. 20
  21. 21 Found 4 unique roots (run '!gcroot -all' to see all roots).
复制代码
                    OSID 是 3a00 的线程是主线程,也就是我们当前操作的线程。我们可以去 OSID 是 3170 的线程去看看,首先,切换线程,执行命令【~~[3170]s】。
                    继续执行【!clrstack -a】命令,查看当前的托管线程调用栈。
  1. 1 0:000> !threads
  2. 2 ThreadCount:      3
  3. 3 UnstartedThread:  0
  4. 4 BackgroundThread: 1
  5. 5 PendingThread:    0
  6. 6 DeadThread:       0
  7. 7 Hosted Runtime:   no
  8. 8 1 0:001> ~0s
  9. 2 ntdll!NtDeviceIoControlFile+0x14:
  10. 3 00007ffd`cf30d0c4 c3              ret
  11. 4
  12. 5 0:000> !ClrStack -a
  13. 6 OS Thread Id: 0x598 (0)
  14. 7         Child SP               IP Call Site
  15. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  16. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  17. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  18. 11     PARAMETERS:
  19. 12         hConsoleInput = <no data>
  20. 13         buffer = <no data>
  21. 14         numInputRecords_UseOne = <no data>
  22. 15         numEventsRead = <no data>
  23. 16     LOCALS:
  24. 17         <no data>
  25. 18         <no data>
  26. 19         <no data>
  27. 20         <no data>
  28. 21         <no data>
  29. 22         <no data>
  30. 23         <no data>
  31. 24
  32. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  33. 26     PARAMETERS:
  34. 27         intercept (<CLR reg>) = 0x0000000000000000
  35. 28     LOCALS:
  36. 29         <no data>
  37. 30         <no data>
  38. 31         <no data>
  39. 32         <no data>
  40. 33         <no data>
  41. 34         <no data>
  42. 35         <no data>
  43. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  44. 37         <no data>
  45. 38         <no data>
  46. 39         <no data>
  47. 40         <no data>
  48. 41         <no data>
  49. 42
  50. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  51. 44     PARAMETERS:
  52. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  53. 46     LOCALS:
  54. 47         0x00000087DC9CE658 = 0x00000197a6009628 1 0:001> ~0s
  55. 2 ntdll!NtDeviceIoControlFile+0x14:
  56. 3 00007ffd`cf30d0c4 c3              ret
  57. 4
  58. 5 0:000> !ClrStack -a
  59. 6 OS Thread Id: 0x598 (0)
  60. 7         Child SP               IP Call Site
  61. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  62. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  63. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  64. 11     PARAMETERS:
  65. 12         hConsoleInput = <no data>
  66. 13         buffer = <no data>
  67. 14         numInputRecords_UseOne = <no data>
  68. 15         numEventsRead = <no data>
  69. 16     LOCALS:
  70. 17         <no data>
  71. 18         <no data>
  72. 19         <no data>
  73. 20         <no data>
  74. 21         <no data>
  75. 22         <no data>
  76. 23         <no data>
  77. 24
  78. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  79. 26     PARAMETERS:
  80. 27         intercept (<CLR reg>) = 0x0000000000000000
  81. 28     LOCALS:
  82. 29         <no data>
  83. 30         <no data>
  84. 31         <no data>
  85. 32         <no data>
  86. 33         <no data>
  87. 34         <no data>
  88. 35         <no data>
  89. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  90. 37         <no data>
  91. 38         <no data>
  92. 39         <no data>
  93. 40         <no data>
  94. 41         <no data>
  95. 42
  96. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  97. 44     PARAMETERS:
  98. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  99. 46     LOCALS:
  100. 47         0x00000087DC9CE658 = 0x00000197a6009628 1 0:001> ~0s
  101. 2 ntdll!NtDeviceIoControlFile+0x14:
  102. 3 00007ffd`cf30d0c4 c3              ret
  103. 4
  104. 5 0:000> !ClrStack -a
  105. 6 OS Thread Id: 0x598 (0)
  106. 7         Child SP               IP Call Site
  107. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  108. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  109. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  110. 11     PARAMETERS:
  111. 12         hConsoleInput = <no data>
  112. 13         buffer = <no data>
  113. 14         numInputRecords_UseOne = <no data>
  114. 15         numEventsRead = <no data>
  115. 16     LOCALS:
  116. 17         <no data>
  117. 18         <no data>
  118. 19         <no data>
  119. 20         <no data>
  120. 21         <no data>
  121. 22         <no data>
  122. 23         <no data>
  123. 24
  124. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  125. 26     PARAMETERS:
  126. 27         intercept (<CLR reg>) = 0x0000000000000000
  127. 28     LOCALS:
  128. 29         <no data>
  129. 30         <no data>
  130. 31         <no data>
  131. 32         <no data>
  132. 33         <no data>
  133. 34         <no data>
  134. 35         <no data>
  135. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  136. 37         <no data>
  137. 38         <no data>
  138. 39         <no data>
  139. 40         <no data>
  140. 41         <no data>
  141. 42
  142. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  143. 44     PARAMETERS:
  144. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  145. 46     LOCALS:
  146. 47         0x00000087DC9CE658 = 0x00000197a6009628 1 0:001> ~0s
  147. 2 ntdll!NtDeviceIoControlFile+0x14:
  148. 3 00007ffd`cf30d0c4 c3              ret
  149. 4
  150. 5 0:000> !ClrStack -a
  151. 6 OS Thread Id: 0x598 (0)
  152. 7         Child SP               IP Call Site
  153. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  154. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  155. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  156. 11     PARAMETERS:
  157. 12         hConsoleInput = <no data>
  158. 13         buffer = <no data>
  159. 14         numInputRecords_UseOne = <no data>
  160. 15         numEventsRead = <no data>
  161. 16     LOCALS:
  162. 17         <no data>
  163. 18         <no data>
  164. 19         <no data>
  165. 20         <no data>
  166. 21         <no data>
  167. 22         <no data>
  168. 23         <no data>
  169. 24
  170. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  171. 26     PARAMETERS:
  172. 27         intercept (<CLR reg>) = 0x0000000000000000
  173. 28     LOCALS:
  174. 29         <no data>
  175. 30         <no data>
  176. 31         <no data>
  177. 32         <no data>
  178. 33         <no data>
  179. 34         <no data>
  180. 35         <no data>
  181. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  182. 37         <no data>
  183. 38         <no data>
  184. 39         <no data>
  185. 40         <no data>
  186. 41         <no data>
  187. 42
  188. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  189. 44     PARAMETERS:
  190. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  191. 46     LOCALS:
  192. 47         0x00000087DC9CE658 = 0x00000197a6009628             Lock
  193. 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
  194. 10    0    1     <strong>3a00</strong> 0000014C5B4C6430    2a020 Preemptive  0000014C5F8098B0:0000014C5F80A618 0000014C5B4BBF70 -00001 MTA
  195. 11    6    2     35e0 0000014C5B56BC40    21220 Preemptive  0000000000000000:0000000000000000 0000014C5B4BBF70 -00001 Ukn (Finalizer)
  196. 12    8    4     <strong>3170</strong> 0000014C5B4D1E80  202b020 Preemptive  0000014C5F80AC88:0000014C5F80C638 0000014C5B4BBF70 -00001 MTA
复制代码
                    我们看到在 ExampleCore_5_3.Program.Worker 方法里有引用了 ExampleCore_5_3.Name 类型。这就找到了 ExampleCore_5_3.Name 类型的所有根引用。

                2)、Windbg Preview 调试
                    编译项目,打开【Windbg Preview】调试器,依次点击【文件】---【Launch executable】,加载我们的项目文件:ExampleCore_5_3.exe,进入到调试器。
                    我们进入调试器后,直接【g】运行调试器,直到我们的控制台程序输出“Press any key to Exit”字样。效果如图:
                    

                    我们在调试器上点击【break】按钮,进入中断模式。
                    由于手动中断,我们必须切换到托管线程上下文,因为目前是在调试器的线程上下文中。
  1. 1 0:008> !clrstack -a
  2. 2 OS Thread Id: 0x3170 (8)
  3. 3         Child SP               IP Call Site
  4. 4 00000030731FF838 00007ff8bec2d664 [HelperMethodFrame: 00000030731ff838] System.Threading.Thread.SleepInternal(Int32)
  5. 5 00000030731FF930 00007FF7AD521E21 System.Threading.Thread.Sleep(Int32)
  6. 6     PARAMETERS:
  7. 7         millisecondsTimeout = <no data>
  8. 8
  9. 9 00000030731FF960 00007FF7AD521CCD ExampleCore_5_3.Program.Worker(System.Object)
  10. 10     PARAMETERS:
  11. 11         this (0x00000030731FF9C0) = 0x0000014c5f809640
  12. 12         o (0x00000030731FF9C8) = <strong>0x0000014c5f809660(这是传入的参数,也就是 Worker 方法的 o 参数。)</strong>
  13. 13     LOCALS:
  14. 14         0x00000030731FF9A8 = <strong>0x0000014c5f809660(这里就是 n1 局部变量的值,代码就是:var n1 = (Name)o!)</strong>
  15. 15         0x00000030731FF9A4 = 0x0000000000000000
  16. 16         0x00000030731FF9A0 = 0x0000000000000001
  17. 17
  18. 18 00000030731FFC10 00007ff80d08b8d3 [DebuggerU2MCatchHandlerFrame: 00000030731ffc10]
复制代码
                    我们必须先找到我们目标对象的地址,所以先使用【!clrstack -a】查看一下托管线程调用栈。
  1. 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007fff`cc08d0c4 c3              ret
复制代码
                    0x000001e689c09660 地址有了,我们还是要确定一下是不是 Name 类型的,可以使用【!DumpObj 0x000001e689c09660】命令。
  1. 1 0:000> !ClrStack -a
  2. 2 OS Thread Id: 0x1fa0 (0)
  3. 3         Child SP               IP Call Site
  4. 4 000000BEF817E6F8 00007fffcc08d0c4 [InlinedCallFrame: 000000bef817e6f8]
  5. 5 000000BEF817E6F8 00007fff1a4d787a [InlinedCallFrame: 000000bef817e6f8]
  6. 6 000000BEF817E6D0 00007fff1a4d787a Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  7. 7     PARAMETERS:
  8. 8         hConsoleInput = <no data>
  9. 9         buffer = <no data>
  10. 10         numInputRecords_UseOne = <no data>
  11. 11         numEventsRead = <no data>
  12. 12     LOCALS:
  13. 13         <no data>
  14. 14         <no data>
  15. 15         <no data>
  16. 16         <no data>
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20
  21. 21 000000BEF817E7C0 00007fff1a4daa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  22. 22     PARAMETERS:
  23. 23         intercept (<CLR reg>) = 0x0000000000000000
  24. 24     LOCALS:
  25. 25         <no data>
  26. 26         <no data>
  27. 27         <no data>
  28. 28         <no data>
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         0x000000BEF817E800 = 0x000001e689c09868
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         <no data>
  37. 37         <no data>
  38. 38
  39. 39 000000BEF817E880 00007ffea92f1af2 ExampleCore_5_3.Program.Run() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\Program.cs @ 47]
  40. 40     PARAMETERS:
  41. 41         this (0x000000BEF817E8E0) = 0x000001e689c09640
  42. 42     LOCALS:
  43. 43         0x000000BEF817E8C8 = <strong>0x000001e689c09660(这就是 Name 类型在托管堆中的地址)</strong>
  44. 44
  45. 45 000000BEF817E8E0 00007ffea92f1988 ExampleCore_5_3.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\Program.cs @ 33]
  46. 46     PARAMETERS:
  47. 47         args (0x000000BEF817E920) = 0x000001e689c08ea0
  48. 48     LOCALS:
  49. 49         0x000000BEF817E908 = 0x000001e689c09640
复制代码
                    证明我们的说法,既然我们得到了对象的地址,我们就可以针对该地址使用【!gcroot 000001e689c09660】命令,查看一下它的根引用。
  1. 1 0:000> !DumpObj 0x000001e689c09660
  2. 2 Name:        ExampleCore_5_3.Name
  3. 3 MethodTable: 00007ffea93a94b0
  4. 4 EEClass:     00007ffea93b2068
  5. 5 Tracked Type: false
  6. 6 Size:        32(0x20) bytes
  7. 7 File:        E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\bin\Debug\net8.0\ExampleCore_5_3.dll
  8. 8 Fields:
  9. 9               MT    Field   Offset                 Type VT     Attr            Value Name
  10. 10 00007ffea92dec08  4000001        8        System.String  0 instance 000002271bfd04e0 _first
  11. 11 00007ffea92dec08  4000002       10        System.String  0 instance 000002271bfd0500 _last
复制代码
                    我们可以使用【!t】或者【!threads】命令,列出所有的托管线程来查看上面的出现的两个线程。
  1. 1 0:000> !gcroot 0x0000017750409660
  2. 2 Caching GC roots, this may take a while.
  3. 3 Subsequent runs of this command will be faster.
  4. 4
  5. 5 HandleTable:<strong>(这里是句柄表)
  6. </strong> 6     000001774c0813e8 (strong handle)
  7. 7           -> 01774dc00028     System.Object[]
  8. 8           -> 017750409660     ExampleCore_5_3.Name
  9. 9
  10. 10 Thread 574:<strong>(这是一个线程,OSID 是 574,该线程是主线程)
  11. </strong>11     52e5f7e630 7ff7a99b1af2 ExampleCore_5_3.Program.Run() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\Program.cs @ 47]
  12. 12         rbp-8: 00000052e5f7e678
  13. 13           -> 017750409660     ExampleCore_5_3.Name
  14. 14
  15. 15 Thread 36e8:<strong>(这是一个线程,OSID 是 36e8,该线程是通过 New Thread 创建的)
  16. </strong>16     52e6b7f480 7ff7a99b1ccd ExampleCore_5_3.Program.Worker(System.Object) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\Program.cs @ 59]
  17. 17         rbp-8: 00000052e6b7f4c8
  18. 18           -> 017750409660     ExampleCore_5_3.Name
  19. 19
  20. 20         rbp+18: 00000052e6b7f4e8
  21. 21           -> 017750409660     ExampleCore_5_3.Name
  22. 22
  23. 23 Found 4 unique roots.
复制代码
                    在这里说明一下,这里【!gcroot】命令的输出内容和原著书上输出的内容是由很大区别的,平台不一样了。
                    我们在使用【!gcroot】命令输出的结果中,有两个线程的输出,我们可以切换到线程上查看详情。
                    首先我们先切换到 OSID 为 574 的线程上,执行命令【~~[574]s】,查看一下具体情况。
  1. 1 0:000> !t
  2. 2 ThreadCount:      3
  3. 3 UnstartedThread:  0
  4. 4 BackgroundThread: 1
  5. 5 PendingThread:    0
  6. 6 DeadThread:       0
  7. 7 Hosted Runtime:   no
  8. 8 1 0:001> ~0s
  9. 2 ntdll!NtDeviceIoControlFile+0x14:
  10. 3 00007ffd`cf30d0c4 c3              ret
  11. 4
  12. 5 0:000> !ClrStack -a
  13. 6 OS Thread Id: 0x598 (0)
  14. 7         Child SP               IP Call Site
  15. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  16. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  17. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  18. 11     PARAMETERS:
  19. 12         hConsoleInput = <no data>
  20. 13         buffer = <no data>
  21. 14         numInputRecords_UseOne = <no data>
  22. 15         numEventsRead = <no data>
  23. 16     LOCALS:
  24. 17         <no data>
  25. 18         <no data>
  26. 19         <no data>
  27. 20         <no data>
  28. 21         <no data>
  29. 22         <no data>
  30. 23         <no data>
  31. 24
  32. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  33. 26     PARAMETERS:
  34. 27         intercept (<CLR reg>) = 0x0000000000000000
  35. 28     LOCALS:
  36. 29         <no data>
  37. 30         <no data>
  38. 31         <no data>
  39. 32         <no data>
  40. 33         <no data>
  41. 34         <no data>
  42. 35         <no data>
  43. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  44. 37         <no data>
  45. 38         <no data>
  46. 39         <no data>
  47. 40         <no data>
  48. 41         <no data>
  49. 42
  50. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  51. 44     PARAMETERS:
  52. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  53. 46     LOCALS:
  54. 47         0x00000087DC9CE658 = 0x00000197a6009628 1 0:001> ~0s
  55. 2 ntdll!NtDeviceIoControlFile+0x14:
  56. 3 00007ffd`cf30d0c4 c3              ret
  57. 4
  58. 5 0:000> !ClrStack -a
  59. 6 OS Thread Id: 0x598 (0)
  60. 7         Child SP               IP Call Site
  61. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  62. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  63. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  64. 11     PARAMETERS:
  65. 12         hConsoleInput = <no data>
  66. 13         buffer = <no data>
  67. 14         numInputRecords_UseOne = <no data>
  68. 15         numEventsRead = <no data>
  69. 16     LOCALS:
  70. 17         <no data>
  71. 18         <no data>
  72. 19         <no data>
  73. 20         <no data>
  74. 21         <no data>
  75. 22         <no data>
  76. 23         <no data>
  77. 24
  78. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  79. 26     PARAMETERS:
  80. 27         intercept (<CLR reg>) = 0x0000000000000000
  81. 28     LOCALS:
  82. 29         <no data>
  83. 30         <no data>
  84. 31         <no data>
  85. 32         <no data>
  86. 33         <no data>
  87. 34         <no data>
  88. 35         <no data>
  89. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  90. 37         <no data>
  91. 38         <no data>
  92. 39         <no data>
  93. 40         <no data>
  94. 41         <no data>
  95. 42
  96. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  97. 44     PARAMETERS:
  98. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  99. 46     LOCALS:
  100. 47         0x00000087DC9CE658 = 0x00000197a6009628 1 0:001> ~0s
  101. 2 ntdll!NtDeviceIoControlFile+0x14:
  102. 3 00007ffd`cf30d0c4 c3              ret
  103. 4
  104. 5 0:000> !ClrStack -a
  105. 6 OS Thread Id: 0x598 (0)
  106. 7         Child SP               IP Call Site
  107. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  108. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  109. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  110. 11     PARAMETERS:
  111. 12         hConsoleInput = <no data>
  112. 13         buffer = <no data>
  113. 14         numInputRecords_UseOne = <no data>
  114. 15         numEventsRead = <no data>
  115. 16     LOCALS:
  116. 17         <no data>
  117. 18         <no data>
  118. 19         <no data>
  119. 20         <no data>
  120. 21         <no data>
  121. 22         <no data>
  122. 23         <no data>
  123. 24
  124. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  125. 26     PARAMETERS:
  126. 27         intercept (<CLR reg>) = 0x0000000000000000
  127. 28     LOCALS:
  128. 29         <no data>
  129. 30         <no data>
  130. 31         <no data>
  131. 32         <no data>
  132. 33         <no data>
  133. 34         <no data>
  134. 35         <no data>
  135. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  136. 37         <no data>
  137. 38         <no data>
  138. 39         <no data>
  139. 40         <no data>
  140. 41         <no data>
  141. 42
  142. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  143. 44     PARAMETERS:
  144. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  145. 46     LOCALS:
  146. 47         0x00000087DC9CE658 = 0x00000197a6009628 1 0:001> ~0s
  147. 2 ntdll!NtDeviceIoControlFile+0x14:
  148. 3 00007ffd`cf30d0c4 c3              ret
  149. 4
  150. 5 0:000> !ClrStack -a
  151. 6 OS Thread Id: 0x598 (0)
  152. 7         Child SP               IP Call Site
  153. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  154. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  155. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  156. 11     PARAMETERS:
  157. 12         hConsoleInput = <no data>
  158. 13         buffer = <no data>
  159. 14         numInputRecords_UseOne = <no data>
  160. 15         numEventsRead = <no data>
  161. 16     LOCALS:
  162. 17         <no data>
  163. 18         <no data>
  164. 19         <no data>
  165. 20         <no data>
  166. 21         <no data>
  167. 22         <no data>
  168. 23         <no data>
  169. 24
  170. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  171. 26     PARAMETERS:
  172. 27         intercept (<CLR reg>) = 0x0000000000000000
  173. 28     LOCALS:
  174. 29         <no data>
  175. 30         <no data>
  176. 31         <no data>
  177. 32         <no data>
  178. 33         <no data>
  179. 34         <no data>
  180. 35         <no data>
  181. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  182. 37         <no data>
  183. 38         <no data>
  184. 39         <no data>
  185. 40         <no data>
  186. 41         <no data>
  187. 42
  188. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  189. 44     PARAMETERS:
  190. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  191. 46     LOCALS:
  192. 47         0x00000087DC9CE658 = 0x00000197a6009628             Lock  
  193. 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
  194. 10    0    1      574 000001774C11D510    2a020 Preemptive  00000177504098B0:000001775040A618 000001774c112fa0 -00001 MTA
  195. 11    6    2     3a3c 000001774C1C2C10    21220 Preemptive  0000000000000000:0000000000000000 000001774c112fa0 -00001 Ukn (Finalizer)
  196. 12    8    4     36e8 000001774C1295F0  202b020 Preemptive  000001775040AC88:000001775040C638 000001774c112fa0 -00001 MTA
复制代码
                    其实OSID 是 574 的线程就是主线程,【!clrstack -a】命令和【!gcroot】命令输出结果和前面是一样的。我们在切换到 OSID 是 36e8 的线程上看看具体情况。
  1. 1 0:000> ~~[574]s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ff8`bec2d0c4 c3              ret
复制代码
                    继续使用【!clrstack -a】命令查看托管线程调用栈的情况。
  1. 1 0:000> ~~[36e8]s
  2. 2 ntdll!NtDelayExecution+0x14:
  3. 3 00007ff8`bec2d664 c3              ret
复制代码
                    我们看到了在 ExampleCore_5_3.Program.Worker 方法的调用栈中有一个局部变量的地址是有点眼熟的,0x0000017750409660,这个地址就是我们 Name 类型在托管堆上的地址。说明,在编号为 0x36e8 这个线程里也引用了我们的 Name 类型。
                    如果大家不信,可以使用【!do 0x0000017750409660】命令或者【!DumpObj 0x0000017750409660】命令证明一下。
  1. 1 0:008> !clrstack -a
  2. 2 OS Thread Id: 0x36e8 (8)
  3. 3         Child SP               IP Call Site
  4. 4 00000052E6B7F358 00007ff8bec2d664 [HelperMethodFrame: 00000052e6b7f358] System.Threading.Thread.SleepInternal(Int32)
  5. 5 00000052E6B7F450 00007ff8083fe5a1 System.Threading.Thread.Sleep(Int32) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs @ 367]
  6. 6     PARAMETERS:
  7. 7         millisecondsTimeout = <no data>
  8. 8
  9. 9 00000052E6B7F480 00007ff7a99b1ccd ExampleCore_5_3.Program.Worker(System.Object) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\Program.cs @ 59]
  10. 10     PARAMETERS:
  11. 11         this (0x00000052E6B7F4E0) = 0x0000017750409640
  12. 12         o (0x00000052E6B7F4E8) = <strong>0x0000017750409660</strong>
  13. 13     LOCALS:
  14. 14         0x00000052E6B7F4C8 = <strong>0x0000017750409660</strong>
  15. 15         0x00000052E6B7F4C4 = 0x0000000000000000
  16. 16         0x00000052E6B7F4C0 = 0x0000000000000001
  17. 17
  18. 18 00000052E6B7F730 00007ff80950b8d3 [DebuggerU2MCatchHandlerFrame: 00000052e6b7f730]
复制代码
        3.2.3、终结操作
            A、基础知识
                当我们声明的类型使用一些非托管资源的时候,例如:文件句柄、数据库连接、互斥体等,就需要做特别的处理,GC 才能安全、可靠的回收该对象所占的资源。如果处理不当,虽然托管对象所占用的内存被回收了,但是对象所使用的非托管资源却不会被回收,因为 GC 并不知道这些非托管资源的存在。

                为了提供合适的回收策略,CLR 引入了终结器的概念,当对象被回收时,它的终结器就会被执行。当这个类被编译为 IL 代码时,终结方法会被编译一个名为 Finalize 的函数。由于,垃圾收集器实际上是一个自动内存管理器,因此,在垃圾收集过程中,它需要执行终结代码。

                当一个类型包含了终结器时,GC 的处理也会有所不同。为了记录哪些对象拥有终结器,GC 维护了一个终结队列(Finalization Queue)。如果在托管堆上创建的对象中包含终结器,那么在创建过程中将被自动放入终结队列中。需要注意,终结队列并没有包含那些被认为是垃圾的对象,而是包含了所有带有终结器并在托管堆上处于活跃状态的对象。

                如果某个带有终结器的对象不存在任何根引用了,并且启动了垃圾回收的过程,那么 GC 会把这个对象放入到另外一个队列中,即 F-Reachable 队列(终结可达队列)。这个队列包含了所有带有终结器并且被作为垃圾的对象,这些对象的终结器都将被执行。在 F-Reachable 队列上的所有对象都被视为仍然存在根引用。需要注意的是:在垃圾收集过程中,并不会执行 F-Reachable 队列中每个对象的终结器的代码,这些代码将在一个特殊的线程中执行,它就是每个 .NET 进程的终结线程(Finalization Thread)。在收到 GC 的请求时,终结线程会启动并且查看 F-Reachable 队列的状态。如果在 F-Reachable 队列上有任何的对象存在,那么它会依次执行这些对象的终结方法。

                在垃圾收集过程结束后,带有终结器的对象会出现在 F-Reachable 队列中(根对象引用存在且是活跃的),直到终结线程执行他们的 Finalize 方法。此时,对象将从 F-Reachable 队列中移走,并且这些对象也被认为不存在根对象引用了,从而真正的被垃圾收集器回收了。

                咱们来一张图举例说明一下,就很容易理解了。
                

                在上图的 步骤1 中分配对象D 和对象E,它们各自带有一个 Finalize 方法。在分配过程中,这些对象除了被放在托管堆上,还被放在终结队列中,表示这些对象不被使用时需要执行终结操作。在 步骤2 中,当垃圾收集过程启动时,对象D 和对象E 都不存在根对象引用。此时,这两个对象将从终结队列中移动到 F-Reachable 队列中,表示可以执行它们的 Finalize 方法了。在接下来的某个时刻,步骤3 会被执行,终结线程也会启动,并开始执行这两个对象的 Finalize 方法。即使在终结器执行完成后,这两个对象仍然存在于 F-Reachable 队列中。最后在 步骤4 中再次启动了垃圾回收过程,这些对象会被移出 F-Reachable 队列(不再有根对象引用),然后又垃圾收集器从托管堆上回收。

                需要注意的是,虽然有一个专门的线程执行 Finalize 方法,但是 CLR 并不能保证这些线程将在何时启动执行。由于在对象中包含了一些资源和在等待资源被回收时需要的时间过长,微软又提出了一种明确的清楚模式,例如:IDisposable 模式或者 Close 模式。当使用终结类型时,背后要做大量的事情,CLR 不仅需要额外的数据结构(终结队列和 F-Reachable 队列),还需要一个专门的线程执行对象的 Finalize 方法。具有终结器的类型,无法仅通过一次垃圾回收操作就被回收,而是需要两次。这些对象会被提升到第 1 代,从而使它成为一种开销较高的对象。

            B、眼见为实
                调试源码:ExampleCore_5_4
                调试任务:通过调试器观察带有终结器的对象是如何被回收的。
                1)、NTSD 调试
                    编译项目,打开【Visual Studio 2022 Developer Command Prompt v17.9.6】命令行工具,输入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_4\bin\Debug\net8.0\ExampleCore_5_4.exe】打开调试器。
                    进入调试器后,直接【g】运行程序,直到调试器输出“Press any key to GC1!”字样。
                    

                    此时,我们按【ctrl+c】组合键,中断调试器的执行,开始我们的调试。
                    直接执行【!FinalizeQueue】命令,查看终结队列的详情。
  1. 1 0:008> !do 0x0000017750409660
  2. 2 Name:        ExampleCore_5_3.Name
  3. 3 MethodTable: 00007ff7a9a694b0
  4. 4 EEClass:     00007ff7a9a72068
  5. 5 Tracked Type: false
  6. 6 Size:        32(0x20) bytes
  7. 7 File:        E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_3\bin\Debug\net8.0\ExampleCore_5_3.dll
  8. 8 Fields:
  9. 9               MT    Field   Offset                 Type VT     Attr            Value Name
  10. 10 00007ff7a999ec08  4000001        8        System.String  0 instance 000001b7e28104e0 _first
  11. 11 00007ff7a999ec08  4000002       10        System.String  0 instance 000001b7e2810500 _last
复制代码
                    此时,我们可以看到第 0 代、第 1 代和第 2 代都没有任何可终结的对象。因为我们还没有执行第一次的【垃圾回收】,但是此时【Ready for finalization 13 objects】说明已经有13个对象可以执行【终结】方法的操作了,这一点和原著是有区别的。
                    我们可以使用【dp 0000013587E3E0E0】命令,查看改地址的保存的数据,其实就是13个要执行 Finalize 方法的对象。
  1. 1 0:002> !FinalizeQueue
  2. 2 SyncBlocks to be cleaned up: 0
  3. 3 Free-Threaded Interfaces to be released: 0
  4. 4 MTA Interfaces to be released: 0
  5. 5 STA Interfaces to be released: 0
  6. 6 ----------------------------------
  7. 7 generation 0 has 0 finalizable objects (0000013587E3E0E0->0000013587E3E0E0)
  8. 8 generation 1 has 0 finalizable objects (0000013587E3E0E0->0000013587E3E0E0)
  9. 9 generation 2 has 0 finalizable objects (0000013587E3E0E0->0000013587E3E0E0)
  10. 10 Ready for finalization 13 objects (0000013587E3E0E0->0000013587E3E148)
  11. 11 Statistics for all finalizable objects (including all objects ready for finalization):
  12. 12               MT    Count    TotalSize Class Name
  13. 13 00007ffeab9694a8        1           24 ExampleCore_5_4_1.NativeEvent
  14. 14 00007ffeab9656f8        2           48 System.WeakReference`1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]]
  15. 15 00007ffeab963d00        4           96 System.WeakReference`1[[System.Diagnostics.Tracing.EventProvider, System.Private.CoreLib]]
  16. 16 00007ffeab9685d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  17. 17 00007ffeab962b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  18. 18 00007ffeab962208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  19. 19 Total 13 objects
复制代码
                    00000135`8c409658 这地址应该就是我们定义的 ExampleCore_5_4_1.NativeEvent 类型。栈地址是有由高到低的分配,我们最早声明 ExampleCore_5_4_1.NativeEvent 类型,它的地址肯定是最高的。执行【!do 00000135`8c409658】命令验证一下。
  1. 1 0:002> dp 0000013587E3E0E0
  2. 2 00000135`87e3e0e0  00000135`8c408fd0 00000135`8c409200
  3. 3 00000135`87e3e0f0  00000135`8c409298 00000135`8c4092b0
  4. 4 00000135`87e3e100  00000135`8c409330 00000135`8c409390
  5. 5 00000135`87e3e110  00000135`8c4094c8 00000135`8c409560
  6. 6 00000135`87e3e120  00000135`8c409578 00000135`8c4095f8
  7. 7 00000135`87e3e130  00000135`8c409610 00000135`8c409628
  8. 8 00000135`87e3e140  <strong>00000135</strong><strong>`8c409658</strong> baadf00d`baadf00d
  9. 9 00000135`87e3e150  baadf00d`baadf00d baadf00d`baadf00d
复制代码
                    接下来,我们【g】继续恢复调试器的执行,完成第一次【垃圾回收】。效果如图:
                    

                    此时,我们在【ctrl+c】组合键进入中断模式,继续执行【!FinalizeQueue】查看终结队列的情况。
  1. 0:002> !do 00000135`8c409658
  2. Name:        ExampleCore_5_4.NativeEvent
  3. MethodTable: 00007ffeab9694a8
  4. EEClass:     00007ffeab971ff0
  5. Tracked Type: false
  6. Size:        24(0x18) bytes
  7. File:        E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_4\bin\Debug\net8.0\ExampleCore_5_4.dll
  8. Fields:
  9.               MT    Field   Offset                 Type VT     Attr            Value Name
  10. 00007ffeab8970a0  4000001        8        System.IntPtr  1 instance 000000000000028C _nativeHandle
复制代码
                    此时,已经经历了第一次的【垃圾回收】,在第 0 代有 13 个可以终结的对象。
                    我们【g】继续恢复调试器的执行,直到调试器输出“Press any key to Exit!”字样。效果如图:
                    

                    此时,已经已经完成第二次的【垃圾回收】了,按【ctrl+c】组合键进入中断模式,我们继续执行【!FinalizeQueue】命令。
  1. 1 0:002> !FinalizeQueue
  2. 2 SyncBlocks to be cleaned up: 0
  3. 3 Free-Threaded Interfaces to be released: 0
  4. 4 MTA Interfaces to be released: 0
  5. 5 STA Interfaces to be released: 0
  6. 6 ----------------------------------
  7. 7 <strong>generation 0 has 13 finalizable objects (0000013587E3E0E0->0000013587E3E148)(执行第一次垃圾回收,第 0 代有 13 个要终结的对象)
  8. </strong> 8 generation 1 has 0 finalizable objects (0000013587E3E0E0->0000013587E3E0E0)
  9. 9 generation 2 has 0 finalizable objects (0000013587E3E0E0->0000013587E3E0E0)
  10. 10 Ready for finalization 0 objects (0000013587E3E148->0000013587E3E148)
  11. 11 Statistics for all finalizable objects (including all objects ready for finalization):
  12. 12               MT    Count    TotalSize Class Name
  13. 13 00007ffeab9694a8        1           24 ExampleCore_5_4_1.NativeEvent
  14. 14 00007ffeab9656f8        2           48 System.WeakReference`1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]]
  15. 15 00007ffeab963d00        4           96 System.WeakReference`1[[System.Diagnostics.Tracing.EventProvider, System.Private.CoreLib]]
  16. 16 00007ffeab9685d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  17. 17 00007ffeab962b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  18. 18 00007ffeab962208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  19. 19 Total 13 objects
复制代码
                    我们看到了结果,对象的生命周期提升了,从第 0 代提升到第 1 代了,也就说明了,局部终结器方法的对象一次是没办法得到回收的,生命周期变长了。
                    我们可以看看所有线程的调用栈,执行命令【~*kn】。
  1. 1 0:002> !FinalizeQueue
  2. 2 SyncBlocks to be cleaned up: 0
  3. 3 Free-Threaded Interfaces to be released: 0
  4. 4 MTA Interfaces to be released: 0
  5. 5 STA Interfaces to be released: 0
  6. 6 ----------------------------------
  7. 7 generation 0 has 0 finalizable objects (0000023E93A0D178->0000023E93A0D178)(第 0 代没有了)
  8. 8 <strong>generation 1 has 13 finalizable objects (0000023E93A0D110->0000023E93A0D178)(第 1 代有了 13 个可以终结的对象,对象生命周期提升了)
  9. </strong> 9 generation 2 has 0 finalizable objects (0000023E93A0D110->0000023E93A0D110)
  10. 10 Ready for finalization 0 objects (0000023E93A0D178->0000023E93A0D178)
  11. 11 Statistics for all finalizable objects (including all objects ready for finalization):
  12. 12               MT    Count    TotalSize Class Name
  13. 13 00007ffeab0d94a8        1           24 ExampleCore_5_4.NativeEvent
  14. 14 00007ffeab0d56f8        2           48 System.WeakReference`1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]]
  15. 15 00007ffeab0d3d00        4           96 System.WeakReference`1[[System.Diagnostics.Tracing.EventProvider, System.Private.CoreLib]]
  16. 16 00007ffeab0d85d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  17. 17 00007ffeab0d2b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  18. 18 00007ffeab0d2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  19. 19 Total 13 objects
复制代码
                    红色标注的就是终结器线程,负责执行带有 Finalize 方法。

                2)、Windbg Preview 调试
                    编译项目,打开【Windbg Preview】调试器,依次点击【文件】---【Launch executable】加载我们的项目文件:ExampleCore_5_4.exe。进入调试器后,我们使用【g】命令,继续运行调试器,直到我们的控制台应用程序输出“Press any key to GC1!”字样,如图:
                    

                    此时,我们点击调试器的【break】按钮,中断调试器的执行。
                    首先我们使用【!FinalizeQueue】命令查看一下进程中可终结对象的状态。
  1.   1 0:009> ~*kn
  2.   2
  3.   3    0  Id: 2200.2154 Suspend: 1 Teb: 00000064`c56e3000 Unfrozen
  4.   4  # Child-SP          RetAddr               Call Site
  5.   5 00 00000064`c597e068 00007fff`dbae7861     ntdll!NtDeviceIoControlFile+0x14
  6.   6 01 00000064`c597e070 00007fff`dbb925c0     KERNELBASE!ConsoleCallServerGeneric+0xe9
  7.   7 02 00000064`c597e1d0 00007fff`dbbefa75     KERNELBASE!GetConsoleInput+0xab3cc
  8.   8 03 00000064`c597e260 00007ffe`a5dd1fb5     KERNELBASE!ReadConsoleInputW+0x15
  9.   9 04 00000064`c597e2a0 00007fff`a6a2aa0a     0x00007ffe`a5dd1fb5
  10. 10 05 00000064`c597e360 00007ffe`a5dd1ac7     System_Console!System.ConsoleKeyInfo System.ConsolePal::ReadKey(System.Boolean)$##60000DB+0xaa
  11. 11 06 00000064`c597e420 00007ffe`a5dd1988     0x00007ffe`a5dd1ac7
  12. 12 07 00000064`c597e490 00007fff`0591b8d3     0x00007ffe`a5dd1988
  13. 13 08 00000064`c597e4e0 00007fff`05850b19     coreclr!CallDescrWorkerInternal+0x83
  14. 14 09 (Inline Function) --------`--------     coreclr!CallDescrWorkerWithHandler+0x56
  15. 15 0a 00000064`c597e520 00007fff`0584d730     coreclr!MethodDescCallSite::CallTargetWorker+0x2a1
  16. 16 0b (Inline Function) --------`--------     coreclr!MethodDescCallSite::Call+0xb
  17. 17 0c 00000064`c597e660 00007fff`05872fc6     coreclr!RunMainInternal+0x11c
  18. 18 0d 00000064`c597e780 00007fff`058732fb     coreclr!RunMain+0xd2
  19. 19 0e 00000064`c597e830 00007fff`057c9141     coreclr!Assembly::ExecuteMainMethod+0x1bf
  20. 20 0f 00000064`c597eb00 00007fff`058de8b8     coreclr!CorHost2::ExecuteAssembly+0x281
  21. 21 10 00000064`c597ec70 00007fff`549f2b76     coreclr!coreclr_execute_assembly+0xd8
  22. 22 11 (Inline Function) --------`--------     hostpolicy!coreclr_t::execute_assembly+0x2a
  23. 23 12 00000064`c597ed10 00007fff`549f2e5c     hostpolicy!run_app_for_context+0x596
  24. 24 13 00000064`c597eea0 00007fff`549f379a     hostpolicy!run_app+0x3c
  25. 25 14 00000064`c597eee0 00007fff`8d9db5c9     hostpolicy!corehost_main+0x15a
  26. 26 15 00000064`c597efe0 00007fff`8d9de066     hostfxr!execute_app+0x2e9
  27. 27 16 00000064`c597f0e0 00007fff`8d9e02ec     hostfxr!`anonymous namespace'::read_config_and_execute+0xa6
  28. 28 17 00000064`c597f1d0 00007fff`8d9de644     hostfxr!fx_muxer_t::handle_exec_host_command+0x16c
  29. 29 18 00000064`c597f280 00007fff`8d9d85a0     hostfxr!fx_muxer_t::execute+0x494
  30. 30 19 00000064`c597f3c0 00007ff7`3043f998     hostfxr!hostfxr_main_startupinfo+0xa0
  31. 31 1a 00000064`c597f4c0 00007ff7`3043fda6     apphost!exe_start+0x878
  32. 32 1b 00000064`c597f690 00007ff7`304412e8     apphost!wmain+0x146
  33. 33 1c (Inline Function) --------`--------     apphost!invoke_main+0x22
  34. 34 1d 00000064`c597f700 00007fff`dd577344     apphost!__scrt_common_main_seh+0x10c
  35. 35 1e 00000064`c597f740 00007fff`de5426b1     KERNEL32!BaseThreadInitThunk+0x14
  36. 36 1f 00000064`c597f770 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  37. 37
  38. 38    1  Id: 2200.33d4 Suspend: 1 Teb: 00000064`c56e5000 Unfrozen
  39. 39  # Child-SP          RetAddr               Call Site
  40. 40 00 00000064`c5affac8 00007fff`de542e27     ntdll!NtWaitForWorkViaWorkerFactory+0x14
  41. 41 01 00000064`c5affad0 00007fff`dd577344     ntdll!TppWorkerThread+0x2f7
  42. 42 02 00000064`c5affdd0 00007fff`de5426b1     KERNEL32!BaseThreadInitThunk+0x14
  43. 43 03 00000064`c5affe00 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  44. 44
  45. 45    2  Id: 2200.2750 Suspend: 1 Teb: 00000064`c56e7000 Unfrozen
  46. 46  # Child-SP          RetAddr               Call Site
  47. 47 00 00000064`c5c7f978 00007fff`de542e27     ntdll!NtWaitForWorkViaWorkerFactory+0x14
  48. 48 01 00000064`c5c7f980 00007fff`dd577344     ntdll!TppWorkerThread+0x2f7
  49. 49 02 00000064`c5c7fc80 00007fff`de5426b1     KERNEL32!BaseThreadInitThunk+0x14
  50. 50 03 00000064`c5c7fcb0 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  51. 51
  52. 52    3  Id: 2200.2418 Suspend: 1 Teb: 00000064`c56e9000 Unfrozen
  53. 53  # Child-SP          RetAddr               Call Site
  54. 54 00 00000064`c5dff5f8 00007fff`de542e27     ntdll!NtWaitForWorkViaWorkerFactory+0x14
  55. 55 01 00000064`c5dff600 00007fff`dd577344     ntdll!TppWorkerThread+0x2f7
  56. 56 02 00000064`c5dff900 00007fff`de5426b1     KERNEL32!BaseThreadInitThunk+0x14
  57. 57 03 00000064`c5dff930 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  58. 58
  59. 59    4  Id: 2200.748 Suspend: 1 Teb: 00000064`c56eb000 Unfrozen ".NET EventPipe"
  60. 60  # Child-SP          RetAddr               Call Site
  61. 61 00 00000064`c5f7f0a8 00007fff`dbb21d20     ntdll!NtWaitForMultipleObjects+0x14
  62. 62 01 00000064`c5f7f0b0 00007fff`dbb21c1e     KERNELBASE!WaitForMultipleObjectsEx+0xf0
  63. 63 02 00000064`c5f7f3a0 00007fff`058f073a     KERNELBASE!WaitForMultipleObjects+0xe
  64. 64 03 00000064`c5f7f3e0 00007fff`058f06a2     coreclr!ds_ipc_poll+0x7e
  65. 65 04 00000064`c5f7f660 00007fff`058f0564     coreclr!ds_ipc_stream_factory_get_next_available_stream+0x12a
  66. 66 05 00000064`c5f7f730 00007fff`dd577344     coreclr!server_thread+0x54
  67. 67 06 00000064`c5f7f7a0 00007fff`de5426b1     KERNEL32!BaseThreadInitThunk+0x14
  68. 68 07 00000064`c5f7f7d0 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  69. 69
  70. 70    5  Id: 2200.3938 Suspend: 1 Teb: 00000064`c56ed000 Unfrozen ".NET Debugger"
  71. 71  # Child-SP          RetAddr               Call Site
  72. 72 00 00000064`c60ff958 00007fff`dbb21d20     ntdll!NtWaitForMultipleObjects+0x14
  73. 73 01 00000064`c60ff960 00007fff`058e9c90     KERNELBASE!WaitForMultipleObjectsEx+0xf0
  74. 74 02 00000064`c60ffc50 00007fff`058e9179     coreclr!DebuggerRCThread::MainLoop+0xe8
  75. 75 03 00000064`c60ffd10 00007fff`058e8fab     coreclr!DebuggerRCThread::ThreadProc+0x139
  76. 76 04 00000064`c60ffd70 00007fff`dd577344     coreclr!DebuggerRCThread::ThreadProcStatic+0x5b
  77. 77 05 00000064`c60ffda0 00007fff`de5426b1     KERNEL32!BaseThreadInitThunk+0x14
  78. 78 06 00000064`c60ffdd0 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  79. 79
  80. 80    6  Id: 2200.3a14 Suspend: 1 Teb: 00000064`c56ef000 Unfrozen ".NET Finalizer"(终结线程)
  81. 81  # Child-SP          RetAddr               Call Site
  82. 82 00 00000064`c627f688 00007fff`dbb21d20     ntdll!NtWaitForMultipleObjects+0x14
  83. 83 01 00000064`c627f690 00007fff`05828f21     KERNELBASE!WaitForMultipleObjectsEx+0xf0
  84. 84 02 00000064`c627f980 00007fff`05828d73     <strong>coreclr!FinalizerThread::WaitForFinalizerEvent</strong>+0x6d
  85. 85 03 00000064`c627f9c0 <strong>00007fff`05874abd</strong>     <strong>coreclr!FinalizerThread::FinalizerThreadWorker</strong>+0x53
  86. 86 04 (Inline Function) --------`--------     coreclr!ManagedThreadBase_DispatchInner+0xd
  87. 87 05 00000064`c627fc10 00007fff`058749d3     coreclr!ManagedThreadBase_DispatchMiddle+0x85
  88. 88 06 00000064`c627fcf0 00007fff`058daea1     coreclr!ManagedThreadBase_DispatchOuter+0xab
  89. 89 07 (Inline Function) --------`--------     coreclr!ManagedThreadBase_NoADTransition+0x28
  90. 90 08 (Inline Function) --------`--------     coreclr!ManagedThreadBase::FinalizerBase+0x28
  91. 91 09 00000064`c627fd90 00007fff`dd577344     coreclr!FinalizerThread::FinalizerThreadStart+0x91
  92. 92 0a 00000064`c627fea0 00007fff`de5426b1     KERNEL32!BaseThreadInitThunk+0x14
  93. 93 0b 00000064`c627fed0 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  94. 94
  95. 95    7  Id: 2200.24fc Suspend: 1 Teb: 00000064`c56fd000 Unfrozen ".NET Tiered Compilation Worker"
  96. 96  # Child-SP          RetAddr               Call Site
  97. 97 00 00000064`c63ff7b8 00007fff`dbaf30ce     ntdll!NtWaitForSingleObject+0x14
  98. 98 01 00000064`c63ff7c0 00007fff`05877d18     KERNELBASE!WaitForSingleObjectEx+0x8e
  99. 99 02 (Inline Function) --------`--------     coreclr!CLREventWaitHelper2+0x6
  100. 100 03 00000064`c63ff860 00007fff`058f5f99     coreclr!CLREventWaitHelper+0x20
  101. 101 04 (Inline Function) --------`--------     coreclr!CLREventBase::WaitEx+0x12
  102. 102 05 (Inline Function) --------`--------     coreclr!CLREventBase::Wait+0x12
  103. 103 06 00000064`c63ff8c0 00007fff`058f5e3c     coreclr!TieredCompilationManager::BackgroundWorkerStart+0x119
  104. 104 07 00000064`c63ff910 00007fff`05874abd     coreclr!TieredCompilationManager::BackgroundWorkerBootstrapper1+0x5c
  105. 105 08 (Inline Function) --------`--------     coreclr!ManagedThreadBase_DispatchInner+0xd
  106. 106 09 00000064`c63ff950 00007fff`058749d3     coreclr!ManagedThreadBase_DispatchMiddle+0x85
  107. 107 0a 00000064`c63ffa30 00007fff`05904c8a     coreclr!ManagedThreadBase_DispatchOuter+0xab
  108. 108 0b (Inline Function) --------`--------     coreclr!ManagedThreadBase_FullTransition+0x24
  109. 109 0c (Inline Function) --------`--------     coreclr!ManagedThreadBase::KickOff+0x24
  110. 110 0d 00000064`c63ffad0 00007fff`dd577344     coreclr!TieredCompilationManager::BackgroundWorkerBootstrapper0+0x3a
  111. 111 0e 00000064`c63ffb20 00007fff`de5426b1     KERNEL32!BaseThreadInitThunk+0x14
  112. 112 0f 00000064`c63ffb50 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  113. 113
  114. 114    8  Id: 2200.20f4 Suspend: 1 Teb: 00000064`c56ff000 Unfrozen
  115. 115  # Child-SP          RetAddr               Call Site
  116. 116 00 00000064`c657efc0 00007fff`de51b44d     ntdll!RtlpAllocateHeap+0x3a
  117. 117 01 00000064`c657f210 00007fff`de5e88d8     ntdll!RtlpAllocateHeapInternal+0xa2d
  118. 118 02 00000064`c657f320 00007fff`de51d255     ntdll!RtlDebugAllocateHeap+0xe8
  119. 119 03 00000064`c657f380 00007fff`de51b44d     ntdll!RtlpAllocateHeap+0xf5
  120. 120 04 00000064`c657f5d0 00007fff`de538373     ntdll!RtlpAllocateHeapInternal+0xa2d
  121. 121 05 00000064`c657f6e0 00007fff`de5381c1     ntdll!LdrpGetNewTlsVector+0x37
  122. 122 06 00000064`c657f710 00007fff`de5077a7     ntdll!LdrpAllocateTls+0x61
  123. 123 07 00000064`c657f7e0 00007fff`de565064     ntdll!LdrpInitializeThread+0x6f
  124. 124 08 00000064`c657f8c0 00007fff`de564c43     ntdll!LdrpInitialize+0x408
  125. 125 09 00000064`c657f960 00007fff`de564bee     ntdll!LdrpInitialize+0x3b
  126. 126 0a 00000064`c657f990 00000000`00000000     ntdll!LdrInitializeThunk+0xe
  127. 127
  128. 128 #  9  Id: 2200.3474 Suspend: 1 Teb: 00000064`c5701000 Unfrozen
  129. 129  # Child-SP          RetAddr               Call Site
  130. 130 00 00000064`c66ffca8 00007fff`de5bca0e     ntdll!DbgBreakPoint
  131. 131 01 00000064`c66ffcb0 00007fff`dd577344     ntdll!DbgUiRemoteBreakin+0x4e
  132. 132 02 00000064`c66ffce0 00007fff`de5426b1     KERNEL32!BaseThreadInitThunk+0x14
  133. 133 03 00000064`c66ffd10 00000000`00000000     ntdll!RtlUserThreadStart+0x21
复制代码
                    在输出的结果中,首先:给出了每一代的终结队列,并给出了每个终结队列本身的地址范围,比如:第 0 代终结队列的起始地址是 23681038090,结束地址是 23681038090。由于没有任何元素,开始和结束地址是一样的。我们可以使用【dp 23681038090】查看它的内容,其实就是【Statistics】统计的内容,有多少个对象实例,就存储了多少项。
  1. 1 0:001> !FinalizeQueue
  2. 2 SyncBlocks to be cleaned up: 0
  3. 3 Free-Threaded Interfaces to be released: 0
  4. 4 MTA Interfaces to be released: 0
  5. 5 STA Interfaces to be released: 0
  6. 6 ----------------------------------
  7. 7
  8. 8 Heap 0
  9. 9 generation 0 has 0 objects (23681038090->23681038090)
  10. 10 generation 1 has 0 objects (23681038090->23681038090)
  11. 11 generation 2 has 0 objects (23681038090->23681038090)
  12. 12 Ready for finalization 0 objects (236810380f8->236810380f8)
  13. 13 ------------------------------
  14. 14 Statistics for all finalizable objects (including all objects ready for finalization):
  15. 15          Address               MT           Size
  16. 16     023685408fd0     7ffa497b2208            400
  17. 17     023685409200     7ffa497b2b28             64
  18. 18     023685409298     7ffa497b3d00             24
  19. 19     0236854092b0     7ffa497b2b28             64
  20. 20     023685409330     7ffa497b3d00             24
  21. 21     023685409390     7ffa497b85d0            184
  22. 22     0236854094c8     7ffa497b2b28             64
  23. 23     023685409560     7ffa497b3d00             24
  24. 24     023685409578     7ffa497b2b28             64
  25. 25     0236854095f8     7ffa497b3d00             24
  26. 26     023685409610     7ffa497b56f8             24
  27. 27     023685409628     7ffa497b56f8             24
  28. 28     023685409658     7ffa497b94b8             24
  29. 29
  30. 30 Statistics:
  31. 31           MT Count TotalSize Class Name
  32. 32 <strong>7ffa497b94b8</strong>     1        24<strong> ExampleCore_5_4.NativeEvent
  33. </strong>33 7ffa497b56f8     2        48 System.WeakReference<System.Diagnostics.Tracing.EventSource>
  34. 34 7ffa497b3d00     4        96 System.WeakReference<System.Diagnostics.Tracing.EventProvider>
  35. 35 7ffa497b85d0     1       184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  36. 36 7ffa497b2b28     4       256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  37. 37 7ffa497b2208     1       400 System.Diagnostics.Tracing.RuntimeEventSource
  38. 38 Total 13 objects, 1,008 bytes
复制代码
                    我们在【Statistics】项的【Count】列的值总和是 13,我红色标注的也是 13 项目,最后3项不算。针对每个地址,我们可以使用【!do】命令或者【!DumpObj】命令来验证。我只输出标红的最后一个(栈的是从高地址到地地址分配,定义越早,地址越大),它是栈顶的地址,这项就是我们定义的 ExampleCore_5_4.NativeEvent
  1. 1 0:001> dp 23681038090
  2. 2 00000236`81038090  00000236`85408fd0 00000236`85409200
  3. 3 00000236`810380a0  00000236`85409298 00000236`854092b0
  4. 4 00000236`810380b0  00000236`85409330 00000236`85409390
  5. 5 00000236`810380c0  00000236`854094c8 00000236`85409560
  6. 6 00000236`810380d0  00000236`85409578 00000236`854095f8
  7. 7 00000236`810380e0  00000236`85409610 00000236`85409628
  8. 8 00000236`810380f0  00000236`85409658 baadf00d`baadf00d
  9. 9 00000236`81038100  baadf00d`baadf00d baadf00d`baadf00d
复制代码
                    从【!FinalizeQueue】命令输出,我们可以看到第 0 代、第 1 代和第 2 代没有任何可终结的对象。

                    【!FinalizeQueue】命令输出中另一个有用的信息就是 F-Reachable 队列。如下所示:
  1. 1 0:001> !do 00000236`85409658
  2. 2 Name:        ExampleCore_5_4.NativeEvent
  3. 3 MethodTable: 00007ffa497b94b8
  4. 4 EEClass:     00007ffa497c1ff0
  5. 5 Tracked Type: false
  6. 6 Size:        24(0x18) bytes
  7. 7 File:        E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_4\bin\Debug\net8.0\ExampleCore_5_4.dll
  8. 8 Fields:
  9. 9               MT    Field   Offset                 Type VT     Attr            Value Name
  10. 10 00007ffa496e70a0  4000001        8        System.IntPtr  1 instance 000000000000028C _nativeHandle
复制代码
                    这个信息表示此时没有任何对象需要执行终结操作。这是正确的,因为垃圾收集器还没有启动。

                    【!FinalizeQueue】命令输出中最后一部分是一些统计信息,其中包括在终结队列中或者 F-Reachable 队列中所有的对象。

                    如果我们想知道进程中包含的所有线程的栈回溯,包括终结线程,我们可以使用【~*kn】命令。
  1. 1 Ready for finalization 0 objects (236810380f8->236810380f8)
复制代码
                    红色标注的就是终结线程调用栈,这个线程正在等待终结器事件(coreclr!FinalizerThread::WaitForFinalizerEvent)。coreclr!FinalizerThread::FinalizerThreadWorker这个方法的返回地址是 00007ffa`a91e4abd ,我们在这个方法上设置一个断点,当终结线程执行工作时就会触发这个断点。我们使用【bp 00007ffa`a9198d73】命令,设置断点。
  1. 1 0:001> ~*kn
  2. 2
  3. 3    0  Id: 39bc.2f20 Suspend: 1 Teb: 0000007d`196e4000 Unfrozen
  4. 4  # Child-SP          RetAddr               Call Site
  5. 5 00 0000007d`1997e528 00007ffb`76617861     ntdll!NtDeviceIoControlFile+0x14
  6. 6 01 0000007d`1997e530 00007ffb`766c25c0     KERNELBASE!ConsoleCallServerGeneric+0xe9
  7. 7 02 0000007d`1997e690 00007ffb`7671fa75     KERNELBASE!GetConsoleInput+0xab3cc
  8. 8 03 0000007d`1997e720 00007ffa`a7c77893     KERNELBASE!ReadConsoleInputW+0x15
  9. 9 04 0000007d`1997e760 00007ffa`a7c7aa0a     System_Console!Interop.Kernel32.ReadConsoleInput+0x83 [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  10. 10 05 0000007d`1997e850 00007ffa`49701a7d     System_Console!System.ConsolePal.ReadKey+0xaa [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  11. 11 06 0000007d`1997e910 00007ffa`49701988     ExampleCore_5_4_1!ExampleCore_5_4_1.Program.Run+0x7d [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_4_1\Program.cs @ 57]
  12. 12 07 0000007d`1997e980 00007ffa`a928b8d3     ExampleCore_5_4_1!ExampleCore_5_4_1.Program.Main+0x58 [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_4_1\Program.cs @ 45]
  13. 13 08 0000007d`1997e9c0 00007ffa`a91c0b19     coreclr!CallDescrWorkerInternal+0x83 [D:\a\_work\1\s\src\coreclr\vm\amd64\CallDescrWorkerAMD64.asm @ 100]
  14. 14 09 (Inline Function) --------`--------     coreclr!CallDescrWorkerWithHandler+0x56 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 67]
  15. 15 0a 0000007d`1997ea00 00007ffa`a91bd730     coreclr!MethodDescCallSite::CallTargetWorker+0x2a1 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 570]
  16. 16 0b (Inline Function) --------`--------     coreclr!MethodDescCallSite::Call+0xb [D:\a\_work\1\s\src\coreclr\vm\callhelpers.h @ 458]
  17. 17 0c 0000007d`1997eb40 00007ffa`a91e2fc6     coreclr!RunMainInternal+0x11c [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1304]
  18. 18 0d 0000007d`1997ec60 00007ffa`a91e32fb     coreclr!RunMain+0xd2 [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1375]
  19. 19 0e 0000007d`1997ed10 00007ffa`a9139141     coreclr!Assembly::ExecuteMainMethod+0x1bf [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1504]
  20. 20 0f 0000007d`1997efe0 00007ffa`a924e8b8     coreclr!CorHost2::ExecuteAssembly+0x281 [D:\a\_work\1\s\src\coreclr\vm\corhost.cpp @ 349]
  21. 21 10 0000007d`1997f150 00007ffa`a9642b76     coreclr!coreclr_execute_assembly+0xd8 [D:\a\_work\1\s\src\coreclr\dlls\mscoree\exports.cpp @ 504]
  22. 22 11 (Inline Function) --------`--------     hostpolicy!coreclr_t::execute_assembly+0x2a [D:\a\_work\1\s\src\native\corehost\hostpolicy\coreclr.cpp @ 109]
  23. 23 12 0000007d`1997f1f0 00007ffa`a9642e5c     hostpolicy!run_app_for_context+0x596 [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 256]
  24. 24 13 0000007d`1997f380 00007ffa`a964379a     hostpolicy!run_app+0x3c [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 285]
  25. 25 14 0000007d`1997f3c0 00007ffa`a969b5c9     hostpolicy!corehost_main+0x15a [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 426]
  26. 26 15 0000007d`1997f4c0 00007ffa`a969e066     hostfxr!execute_app+0x2e9 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 145]
  27. 27 16 0000007d`1997f5c0 00007ffa`a96a02ec     hostfxr!`anonymous namespace'::read_config_and_execute+0xa6 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 532]
  28. 28 17 0000007d`1997f6b0 00007ffa`a969e644     hostfxr!fx_muxer_t::handle_exec_host_command+0x16c [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 1007]
  29. 29 18 0000007d`1997f760 00007ffa`a96985a0     hostfxr!fx_muxer_t::execute+0x494 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 578]
  30. 30 19 0000007d`1997f8a0 00007ff6`50a1f998     hostfxr!hostfxr_main_startupinfo+0xa0 [D:\a\_work\1\s\src\native\corehost\fxr\hostfxr.cpp @ 62]
  31. 31 1a 0000007d`1997f9a0 00007ff6`50a1fda6     apphost!exe_start+0x878 [D:\a\_work\1\s\src\native\corehost\corehost.cpp @ 240]
  32. 32 1b 0000007d`1997fb70 00007ff6`50a212e8     apphost!wmain+0x146 [D:\a\_work\1\s\src\native\corehost\corehost.cpp @ 311]
  33. 33 1c (Inline Function) --------`--------     apphost!invoke_main+0x22 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 90]
  34. 34 1d 0000007d`1997fbe0 00007ffb`781a7344     apphost!__scrt_common_main_seh+0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
  35. 35 1e 0000007d`1997fc20 00007ffb`78d426b1     KERNEL32!BaseThreadInitThunk+0x14
  36. 36 1f 0000007d`1997fc50 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  37. 37
  38. 38 #  1  Id: 39bc.3210 Suspend: 1 Teb: 0000007d`196f8000 Unfrozen
  39. 39  # Child-SP          RetAddr               Call Site
  40. 40 00 0000007d`19affc28 00007ffb`78dbca0e     ntdll!DbgBreakPoint
  41. 41 01 0000007d`19affc30 00007ffb`781a7344     ntdll!DbgUiRemoteBreakin+0x4e
  42. 42 02 0000007d`19affc60 00007ffb`78d426b1     KERNEL32!BaseThreadInitThunk+0x14
  43. 43 03 0000007d`19affc90 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  44. 44
  45. 45    4  Id: 39bc.1e08 Suspend: 1 Teb: 0000007d`196ec000 Unfrozen ".NET EventPipe"
  46. 46  # Child-SP          RetAddr               Call Site
  47. 47 00 0000007d`19f7f658 00007ffb`76651d20     ntdll!NtWaitForMultipleObjects+0x14
  48. 48 01 0000007d`19f7f660 00007ffb`76651c1e     KERNELBASE!WaitForMultipleObjectsEx+0xf0
  49. 49 02 0000007d`19f7f950 00007ffa`a926073a     KERNELBASE!WaitForMultipleObjects+0xe
  50. 50 03 0000007d`19f7f990 00007ffa`a92606a2     coreclr!ds_ipc_poll+0x7e [D:\a\_work\1\s\src\native\eventpipe\ds-ipc-pal-namedpipe.c @ 240]
  51. 51 04 0000007d`19f7fc10 00007ffa`a9260564     coreclr!ds_ipc_stream_factory_get_next_available_stream+0x12a [D:\a\_work\1\s\src\native\eventpipe\ds-ipc.c @ 402]
  52. 52 05 0000007d`19f7fce0 00007ffb`781a7344     coreclr!server_thread+0x54 [D:\a\_work\1\s\src\native\eventpipe\ds-server.c @ 129]
  53. 53 06 0000007d`19f7fd50 00007ffb`78d426b1     KERNEL32!BaseThreadInitThunk+0x14
  54. 54 07 0000007d`19f7fd80 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  55. 55
  56. 56    5  Id: 39bc.9c8 Suspend: 1 Teb: 0000007d`196ee000 Unfrozen ".NET Debugger"
  57. 57  # Child-SP          RetAddr               Call Site
  58. 58 00 0000007d`1a0ff7e8 00007ffb`76651d20     ntdll!NtWaitForMultipleObjects+0x14
  59. 59 01 0000007d`1a0ff7f0 00007ffa`a9259c90     KERNELBASE!WaitForMultipleObjectsEx+0xf0
  60. 60 02 0000007d`1a0ffae0 00007ffa`a9259179     coreclr!DebuggerRCThread::MainLoop+0xe8 [D:\a\_work\1\s\src\coreclr\debug\ee\rcthread.cpp @ 927]
  61. 61 03 0000007d`1a0ffba0 00007ffa`a9258fab     coreclr!DebuggerRCThread::ThreadProc+0x139 [D:\a\_work\1\s\src\coreclr\debug\ee\rcthread.cpp @ 730]
  62. 62 04 0000007d`1a0ffc00 00007ffb`781a7344     coreclr!DebuggerRCThread::ThreadProcStatic+0x5b [D:\a\_work\1\s\src\coreclr\debug\ee\rcthread.cpp @ 1321]
  63. 63 05 0000007d`1a0ffc30 00007ffb`78d426b1     KERNEL32!BaseThreadInitThunk+0x14
  64. 64 06 0000007d`1a0ffc60 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  65. 65
  66. 66    6  <strong>Id: 39bc.14d4 Suspend:</strong> <strong>1</strong> <strong>Teb: 0000007d`196f0000 Unfrozen ".NET Finalizer"(终结线程)</strong>
  67. 67  # Child-SP          RetAddr               Call Site
  68. 68 00 0000007d`1a27f3e8 00007ffb`76651d20     ntdll!NtWaitForMultipleObjects+0x14
  69. 69 01 0000007d`1a27f3f0 00007ffa`a9198f21     KERNELBASE!WaitForMultipleObjectsEx+0xf0
  70. 70 02 0000007d`1a27f6e0 00007ffa`a9198d73     <strong>coreclr!FinalizerThread::WaitForFinalizerEvent</strong>+0x6d [D:\a\_work\1\s\src\coreclr\vm\finalizerthread.cpp @ 173]
  71. 71 03 0000007d`1a27f720 <strong>00007ffa`a91e4abd</strong>     <strong>coreclr!FinalizerThread::FinalizerThreadWorker</strong>+0x53 [D:\a\_work\1\s\src\coreclr\vm\finalizerthread.cpp @ 262]
  72. 72 04 (Inline Function) --------`--------     coreclr!ManagedThreadBase_DispatchInner+0xd [D:\a\_work\1\s\src\coreclr\vm\threads.cpp @ 7222]
  73. 73 05 0000007d`1a27f970 00007ffa`a91e49d3     coreclr!ManagedThreadBase_DispatchMiddle+0x85 [D:\a\_work\1\s\src\coreclr\vm\threads.cpp @ 7266]
  74. 74 06 0000007d`1a27fa50 00007ffa`a924aea1     coreclr!ManagedThreadBase_DispatchOuter+0xab [D:\a\_work\1\s\src\coreclr\vm\threads.cpp @ 7425]
  75. 75 07 (Inline Function) --------`--------     coreclr!ManagedThreadBase_NoADTransition+0x28 [D:\a\_work\1\s\src\coreclr\vm\threads.cpp @ 7494]
  76. 76 08 (Inline Function) --------`--------     coreclr!ManagedThreadBase::FinalizerBase+0x28 [D:\a\_work\1\s\src\coreclr\vm\threads.cpp @ 7513]
  77. 77 09 0000007d`1a27faf0 00007ffb`781a7344     coreclr!FinalizerThread::FinalizerThreadStart+0x91 [D:\a\_work\1\s\src\coreclr\vm\finalizerthread.cpp @ 403]
  78. 78 0a 0000007d`1a27fc00 00007ffb`78d426b1     KERNEL32!BaseThreadInitThunk+0x14
  79. 79 0b 0000007d`1a27fc30 00000000`00000000     ntdll!RtlUserThreadStart+0x21
复制代码
                    使用【g】命令恢复程序的执行,在控制台程序中按任意键触发第一次垃圾回收。直到输出“Press any key to GC2!”字样。
  1. 1 0:001> bp 00007ffa`a91e4abd
复制代码
                    触发了断点。我们再次执行【!FinalizeQueue】命令。
  1. 1 0:007> g
  2. 2 Breakpoint 0 hit
  3. 3 coreclr!ManagedThreadBase_DispatchMiddle+0x85:
  4. 4 00007ffa`b30e4abd 90              nop
复制代码
                第 0 代有 13 个可终结的对象,第 1 代和第 2 代没有任何可终结的对象。
                当我们继续【g】恢复程序的执行,在控制台程序中按任意键触发第二次垃圾回收。一直到控制台输出“Press any key to Exit!”字样。
                回到调试器,点击【break】按钮继续进入到中断模式,继续执行【!FinalizeQueue】命令。
  1. 1 0:007> !FinalizeQueue
  2. 2 SyncBlocks to be cleaned up: 0
  3. 3 Free-Threaded Interfaces to be released: 0
  4. 4 MTA Interfaces to be released: 0
  5. 5 STA Interfaces to be released: 0
  6. 6 ----------------------------------
  7. 7
  8. 8 Heap 0
  9. 9 <strong>generation 0 has 13 objects (26ba90a8080->26ba90a80e8)(第 0 代有 13 个可终结的对象)
  10. </strong>10 generation 1 has 0 objects (26ba90a8080->26ba90a8080)
  11. 11 generation 2 has 0 objects (26ba90a8080->26ba90a8080)
  12. 12 Ready for finalization 0 objects (26ba90a80e8->26ba90a80e8)
  13. 13 ------------------------------
  14. 14 Statistics for all finalizable objects (including all objects ready for finalization):
  15. 15          Address               MT           Size
  16. 16     026bad408fd0     7ffa536e2208            400
  17. 17     026bad409200     7ffa536e2b28             64
  18. 18     026bad409298     7ffa536e3d00             24
  19. 19     026bad4092b0     7ffa536e2b28             64
  20. 20     026bad409330     7ffa536e3d00             24
  21. 21     026bad409390     7ffa536e85d0            184
  22. 22     026bad4094c8     7ffa536e2b28             64
  23. 23     026bad409560     7ffa536e3d00             24
  24. 24     026bad409578     7ffa536e2b28             64
  25. 25     026bad4095f8     7ffa536e3d00             24
  26. 26     026bad409610     7ffa536e56f8             24
  27. 27     026bad409628     7ffa536e56f8             24
  28. 28     026bad409658     7ffa536e94b8             24
  29. 29
  30. 30 Statistics:
  31. 31           MT Count TotalSize Class Name
  32. 32 7ffa536e94b8     1        24 ExampleCore_5_4.NativeEvent
  33. 33 7ffa536e56f8     2        48 System.WeakReference<System.Diagnostics.Tracing.EventSource>
  34. 34 7ffa536e3d00     4        96 System.WeakReference<System.Diagnostics.Tracing.EventProvider>
  35. 35 7ffa536e85d0     1       184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  36. 36 7ffa536e2b28     4       256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  37. 37 7ffa536e2208     1       400 System.Diagnostics.Tracing.RuntimeEventSource
  38. 38 Total 13 objects, 1,008 bytes
复制代码
                我们看到经过第 2 次垃圾回收,那些对象升级到第 1 代了。此时,我们可以使用【!dumpheap -type NativeEvent】找到 NativeEvent 类型的内存地址,然后再使用【!gcroot】命令,还可以找到 NativeEvent类型是有根引用的。
  1. 1 0:001> !FinalizeQueue
  2. 2 SyncBlocks to be cleaned up: 0
  3. 3 Free-Threaded Interfaces to be released: 0
  4. 4 MTA Interfaces to be released: 0
  5. 5 STA Interfaces to be released: 0
  6. 6 ----------------------------------
  7. 7
  8. 8 Heap 0
  9. 9 generation 0 has 0 objects (1ea05688118->1ea05688118)(第 0 代没有了)
  10. 10 <strong>generation 1 has 13 objects (1ea056880b0->1ea05688118)(升级到第 1 代了,对象的生命周期变长了)
  11. </strong>11 generation 2 has 0 objects (1ea056880b0->1ea056880b0)
  12. 12 Ready for finalization 0 objects (1ea05688118->1ea05688118)
  13. 13 ------------------------------
  14. 14 Statistics for all finalizable objects (including all objects ready for finalization):
  15. 15          Address               MT           Size
  16. 16     01ea09c08fd0     7ffa53742208            400
  17. 17     01ea09c09200     7ffa53742b28             64
  18. 18     01ea09c09298     7ffa53743d00             24
  19. 19     01ea09c092b0     7ffa53742b28             64
  20. 20     01ea09c09330     7ffa53743d00             24
  21. 21     01ea09c09390     7ffa537485d0            184
  22. 22     01ea09c094c8     7ffa53742b28             64
  23. 23     01ea09c09560     7ffa53743d00             24
  24. 24     01ea09c09578     7ffa53742b28             64
  25. 25     01ea09c095f8     7ffa53743d00             24
  26. 26     01ea09c09610     7ffa537456f8             24
  27. 27     01ea09c09628     7ffa537456f8             24
  28. 28     01ea09c09658     7ffa537494a8             24
  29. 29
  30. 30 Statistics:
  31. 31           MT Count TotalSize Class Name
  32. 32 7ffa537494a8     1        24 ExampleCore_5_4.NativeEvent
  33. 33 7ffa537456f8     2        48 System.WeakReference<System.Diagnostics.Tracing.EventSource>
  34. 34 7ffa53743d00     4        96 System.WeakReference<System.Diagnostics.Tracing.EventProvider>
  35. 35 7ffa537485d0     1       184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  36. 36 7ffa53742b28     4       256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  37. 37 7ffa53742208     1       400 System.Diagnostics.Tracing.RuntimeEventSource
  38. 38 Total 13 objects, 1,008 bytes
复制代码
                0179a9409658 这个地址就是 ExampleCore_5_4.NativeEvent 类型,我看看还有没有根引用。
  1. 1 0:007> !DumpHeap -type NativeEvent
  2. 2          Address               MT           Size
  3. 3     <strong>0179a9409658</strong>     7ffa51a294a8             24
  4. 4
  5. 5 Statistics:
  6. 6           MT Count TotalSize Class Name
  7. 7 7ffa51a294a8     1        24 ExampleCore_5_4.NativeEvent
  8. 8 Total 1 objects, 24 bytes
复制代码
                说明不能回收。
                我们继续【g】运行调试器。在控制台程序按任意键。我们再次运行【 !gcroot 0179a9409658 】。
  1. 1 0:007> !gcroot 0179a9409658
  2. 2 Caching GC roots, this may take a while.
  3. 3 Subsequent runs of this command will be faster.
  4. 4
  5. 5 Thread 3204:
  6. 6     1ff797ebd0 7ffa51971ab7 ExampleCore_5_4.Program.Run() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_4\Program.cs @ 54]
  7. 7         rbp-10: 0000001ff797ec20
  8. 8           -> 0179a9409658     ExampleCore_5_4.NativeEvent
  9. 9
  10. 10         rbp-8: 0000001ff797ec28
  11. 11           -> 0179a9409658     ExampleCore_5_4.NativeEvent
  12. 12
  13. 13 Found 2 unique roots.
复制代码
                没有任何引用了,可以执行垃圾回收操作了,终结线程就会在合适时机执行。

        3.2.4、回收 GC 内存
            如果在第 0 代和第 1 代上执行的垃圾回收操作会引起托管堆上出现内存空间缝隙,那么 GC 将执行对所有的活跃对象的紧缩操作,这就可以使对象地址相邻,并把托管堆上所有的空闲空间合并成一个更大的内存空间,这个新的内存空间会紧跟在最后一个活跃对象之后。
            以下是一个示意图:
            

            在上图中,在托管堆上的初始状态中包含了 5 个存在根引用的对象(依次A 到 E)。在执行过程的某个时刻,对象 B 和对象 D 没有任何根引用了,将在下一次执行垃圾回收的时候被清理掉。当垃圾操作执行时,会回收对象 B 和对象 D 的空间,这将导致托管堆上出现空间碎片。为了消除空间碎片,GC 会把剩下的所有活跃的对象(对象A、C 和 E)进行紧缩,并将多个空闲的内存块(保存对象B和 D 的内存)合并成一个大的空闲块。最后,根据对象的紧缩和合并的结果来更新当前内存分配指针。
            注意:
              由于达到了所有 3 个代的阈值而使的所有代中的对象都被收集就是【完全垃圾收集】,尽在第 0 代或者第 0 代和第 1 代进行垃圾收集就是【部分垃圾收集】。由于执行紧缩操作的开销和对象的大小成正比(对象越大,紧缩操作的开销越高),所以在托管堆上,有大对象堆和小对象堆之分。

        3.2.5、大对象堆
            A、基础知识
                大对象堆(LOH)包含的对象通常大于或者等于 85 000 个字节。将这种大小的对象单独放入一个堆是有原因的:在垃圾收集的紧缩阶段,在对某个对象执行紧缩操作时的开销是与对象的大小成正比的。因此,没有将大对象放在标准的堆上,而是创建了 LOH。LOH 最好被视为第 2 代内存空间的扩展,并对 LOH 中的对象的收集操作只有在收集完第 2 代中的对象之后才会进行,这也就意味着对 LOH 中对象的收集操作只会在【完全垃圾收集】中进行。
                因为大对象进行压缩操作的开销十分大,所以 GC 会避免在 LOH 上进行紧缩操作,取而代之的就是执行【标记清除】。在这个操作中会维持一个空闲链表,用于跟踪 LOH 内存段中可用内存。如图:
                

                虽然 LOH 没有执行任何紧缩操作,但是它会合并相邻的空闲内存块,并把它添加到空闲链表中。

                总结:LOH堆也就是大对象堆,既没有代的机制,也没有压缩的机制,只有“标记清除”,即:GC 触发时,只会将一个对象标记成 Free 对象。这种 Free 可供后续分配的对象,可以说,以后有新对象产生,会首先存放在 Free 块中。
                当我们通过调试器扩展命令查看 LOH 的时候,发现这个对象会有很多大小小于 85000 的对象,这些对象是有 CLR 堆管理器放在 LOH 上的,有着特殊的作用。通常来说,你可以看到一些由 GC 专门使用的并且小于 85000 字节的对象。
                
            B、眼见为实
                调试源码:ExampleCore_5_5
                调试任务:查看大对象如何在大对象堆上分配和回收
                1)、NTSD 调试
                    编译项目,打开【Visual Studio 2022 Developer Command Prompt v17.9.6】命令行工具,输入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_5\bin\Debug\net8.0\ExampleCore_5_5.exe】打开调试器。
                    进入调试器后,我们直接使用【g】命令运行调试器,直到调试器输出“1、对象已经分配,请查看托管堆!”,并且调试进入中断模式,效果如图:
                    

                    此时,说明内存已经分配了,我们首先使用【!eeheap -gc】命令查看 GC 的详情,主要关注 LOH(大对象堆)。
  1. 1 0:006> !gcroot 0179a9409658
  2. 2 Caching GC roots, this may take a while.
  3. 3 Subsequent runs of this command will be faster.
  4. 4
  5. 5 Found 0 unique roots
复制代码
                    红色标注的就是 LOH,从此我们就能得到 LOH 的开始地址和结束地址,分别是:00000142C1000028-00000142C10D0CA8,有了这个地址范围,我们就可以查看 LOH 有什么对象,使用命令【!DumpHeap 00000142C1000028 00000142C10D0CA8】查看这个地址范围内的所有对象。
  1. 1 0:000> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000142C0C00028
  4. 4 generation 1 starts at 0x00000142C0800028
  5. 5 generation 2 starts at 0x0000018352CE0008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 00000182D21DF320  00000142C0C00028  00000142C0C00028  00000142C0C11000  0x0(0)  0x10fd8(69592)
  10. 10 generation 1:
  11. 11 00000182D21DF270  00000142C0800028  00000142C0800028  00000142C0801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 00000142BE0CC1D0  0000018352CE0008  0000018352CE0A48  0000018352CF0000  0xa40(2624)  0xfff8(65528)
  14. 14 00000182D21DF1C0  00000142C0400028  00000142C0400028  00000142C0401000  0x0(0)  0xfd8(4056)
  15. 15 <strong>Large object</strong> <strong>heap starts at</strong> <strong>0x0000000000000000</strong>
  16. 16 <strong>         segment             begin         allocated         committed    allocated size    committed size
  17. </strong>17 <strong>00000182D21DF3D0  00000142C1000028  00000142C10D0CA8  00000142C10D1000  0xd0c80(855168)  0xd0fd8(856024)
  18. </strong>18 Pinned object heap starts at 0x0000000000000000
  19. 19 00000182D21DEC40  00000142BE400028  00000142BE404018  00000142BE411000  0x3ff0(16368)  0x10fd8(69592)
  20. 20 Total Allocated Size:              Size: 0xd56b0 (874160) bytes.
  21. 21 Total Committed Size:              Size: 0xf3f58 (999256) bytes.
  22. 22 ------------------------------
  23. 23 GC Allocated Heap Size:    Size: 0xd56b0 (874160) bytes.
  24. 24 GC Committed Heap Size:    Size: 0xf3f58 (999256) bytes.
复制代码
                    红色标注的就是我们在 Test() 方法内部初始化的 3 个变量,它们的大小都是大于 85000 字节的,所以都会分配在 LOH 上。
                    我们【g】继续运行调试器,直到调试器输出“2、GC 已经触发,请查看托管堆中的 byte2”,执行垃圾回收,byte2 变量没有根引用,所以会被回收,其它两个变量保存。
  1. 1 0:000> !DumpHeap 00000142C1000028 00000142C10D0CA8
  2. 2          Address               MT     Size
  3. 3 00000142c1000028 00000142bc5e00f0       32 Free
  4. 4 <strong>00000142c1000048 00007ffcea4c9430   185024(这就是 byte1 变量)</strong>
  5. 5 00000142c102d308 00000142bc5e00f0       32 Free
  6. 6 <strong>00000142c102d328 00007ffcea4c9430   285024(这就是 byte2 变量)</strong>
  7. 7 00000142c1072c88 00000142bc5e00f0       32 Free
  8. 8 <strong>00000142c1072ca8 00007ffcea4c9430  </strong> <strong>385024(这就是 byte3 变量)</strong>
  9. 9
  10. 10 Statistics:
  11. 11               MT    Count    TotalSize Class Name
  12. 12 00000142bc5e00f0        3           96      Free
  13. 13 00007ffcea4c9430        3       855072 System.Byte[]
  14. 14 Total 6 objects
复制代码
                    此时,我们再次运行【!DumpHeap 00000142C1000028 00000142C10D0CA8】命令查看 LOH 的情况。
  1. 1 0:000> g
  2. 2 2、GC 已经触发,请查看托管堆中的 byte2
  3. 3 (292c.23a4): Break instruction exception - code 80000003 (first chance)
  4. 4 KERNELBASE!wil::details::DebugBreak+0x2:
  5. 5 00007ffd`ccacb502 cc              int     3
复制代码
                    上面写的很清楚了,byte2 变量已经被回收了,它剩下的空间标记为“Free”,如果此时,我们声明一个对象的大小小于 285088 这数值,这块空间就会直接被使用。
                    【g】命令继续运行调试器,直到调试器输出“3、已分配 byte4,查看是否 Free 块中”字样,我们可以再次查看 LOH 的情况。
  1. 1 0:000> !DumpHeap 00000142C1000028 00000142C10D0CA8
  2. 2          Address               MT     Size
  3. 3 00000142c1000028 00000142bc5e00f0       32 Free
  4. 4 <strong>00000142c1000048 00007ffcea4c9430   185024(变量 byte1 还在)</strong>
  5. 5 00000142c102d308 00000142bc5e00f0   285088 Free(变量 byte2 已经被回收了)
  6. 6 <strong>00000142c1072ca8 00007ffcea4c9430  </strong> <strong>385024(变量 byte3 还在)</strong>
  7. 7
  8. 8 Statistics:
  9. 9               MT    Count    TotalSize Class Name
  10. 10 00000142bc5e00f0        2       285120      Free
  11. 11 00007ffcea4c9430        2       570048 System.Byte[]
  12. 12 Total 4 objects
复制代码
                    再次执行【!DumpHeap 00000142C1000028 00000142C10D0CA8】命令,看看 LOH 的情况。
  1. 1 0:000> g
  2. 2 3、已分配 byte4,查看是否 Free 块中
  3. 3 (292c.23a4): Break instruction exception - code 80000003 (first chance)
  4. 4 KERNELBASE!wil::details::DebugBreak+0x2:
  5. 5 00007ffd`ccacb502 cc              int     3
复制代码
                    上面的内容很好的证明了我们的说法,红色标注的已经说明了问题,分配的 byte4 对象大小正好在 Free 块中,所以就把 byte4 直接存储了。

                2)、Windbg Preview 调试
                    编译项目,打开【Windbg Preview】调试器,依次点击【文件】---【Launch executable】,加载我们的项目文件:ExampleCore_5_5.exe,进入我们的调试器。
                    进入调试器后,我们直接使用【g】命令运行调试器,调试器会自己中断,并且,我们得控制台程序会输出“1、对象已经分配,请查看托管堆!”字样。
                    我们使用【!eeheap -gc】查找 LOH 的地址,有了地址才可以才看堆上的对象。
  1. 1 0:000> !DumpHeap 00000142C1000028 00000142C10D0CA8
  2. 2          Address               MT     Size
  3. 3 00000142c1000028 00000142bc5e00f0       32 Free
  4. 4 <strong>00000142c1000048 00007ffcea4c9430   185024(变量 byte1 还在)</strong>
  5. 5 00000142c102d308 00000142bc5e00f0       32 Free
  6. 6 <strong>00000142c102d328 00007ffcea4c9430   280024(我们重新声明的变量 byte4,大小是280000)</strong>
  7. 7 00000142c1071900 00000142bc5e00f0     5032 Free
  8. 8 <strong>00000142c1072ca8 00007ffcea4c9430  </strong> <strong>385024(变量 byte3 还在)</strong>
  9. 9
  10. 10 Statistics:
  11. 11               MT    Count    TotalSize Class Name
  12. 12 00000142bc5e00f0        3         5096      Free
  13. 13 00007ffcea4c9430        3       850072 System.Byte[]
  14. 14 Total 6 objects
复制代码
                    红色标注的就是 LOH 区域,由于我们的对象最小都是 85000,所以其他的堆都不用关心,直接查看 LOH。
                    我们看到 LOH 的起始地址是 028f4d800028,我们就可以使用【!DumpHeap 028f4d800028】命令,查看LOH 有什么对象了。
  1. 1 0:000> !eeheap -gc
  2. 2
  3. 3 ========================================
  4. 4 Number of GC Heaps: 1
  5. 5 ----------------------------------------
  6. 6 Small object heap
  7. 7          segment            begin        allocated        committed allocated size   committed size  
  8. 8 generation 0:
  9. 9     02cf5e8ff320     028f4d400028     028f4d40a630     028f4d411000 0xa608 (42504)   0x11000 (69632)
  10. 10 generation 1:
  11. 11     02cf5e8ff270     028f4d000028     028f4d000028     028f4d001000                  0x1000 (4096)   
  12. 12 generation 2:
  13. 13     02cf5e8ff1c0     028f4cc00028     028f4cc00028     028f4cc01000                  0x1000 (4096)   
  14. 14 NonGC heap
  15. 15          segment            begin        allocated        committed allocated size   committed size  
  16. 16     028f48ce81e0     02cfdf400008     02cfdf400a48     02cfdf410000 0xa40 (2624)     0x10000 (65536)
  17. 17 <strong>Large object heap
  18. </strong>18 <strong>         segment            begin        allocated        committed allocated size   committed size  
  19. </strong>19     <strong>02cf5e8ff3d0     028f4d800028     028f4d8d0ca8     028f4d8d1000 0xd0c80 (855168) 0xd1000 (856064)
  20. </strong>20 Pinned object heap
  21. 21          segment            begin        allocated        committed allocated size   committed size  
  22. 22     02cf5e8fec40     028f4ac00028     028f4ac04018     028f4ac11000 0x3ff0 (16368)   0x11000 (69632)
  23. 23 ------------------------------
  24. 24 GC Allocated Heap Size:    Size: 0xdfcb8 (916664) bytes.
  25. 25 GC Committed Heap Size:    Size: 0x105000 (1069056) bytes.
复制代码
                    这个命令输出的内容很多,当然,我们可以使用【!DumpHeap 028f4d800028 028f4d8d0ca8】命令,查看我们关注的东西。
  1. 1 0:000> !dumpheap 028f4d800028
  2. 2          Address               MT           Size
  3. 3     028f4d800028     028f48d0c320             32 Free
  4. 4     <strong>028f4d800048</strong>     <strong>7ffea05e9430        185,024</strong> (byte1)
  5. 5     028f4d82d308     028f48d0c320             32 Free
  6. 6     <strong>028f4d82d328     7ffea05e9430        285,024</strong> (byte2)
  7. 7     028f4d872c88     028f48d0c320             32 Free
  8. 8     <strong>028f4d872ca8     7ffea05e9430        385,024</strong> (byte3)
  9. 9     02cfdf400008     7ffea051ec08             24
  10. 10     02cfdf400020     7ffea046a318             40
  11. 11     02cfdf400048     7ffea051ec08            150
  12. 12     02cfdf4000e0     7ffea051ec08            122
  13. 13     02cfdf400160     7ffea051ec08             42
  14. 14     02cfdf400190     7ffea051ec08             30
  15. 15     02cfdf4001b0     7ffea051ec08             50
  16. 16     02cfdf4001e8     7ffea051ec08             38
  17. 17     02cfdf400210     7ffea051ec08             26
  18. 18     02cfdf400230     7ffea051ec08             34
  19. 19     02cfdf400258     7ffea051ec08            118
  20. 20     02cfdf4002d0     7ffea051ec08            126
  21. 21     02cfdf400350     7ffea05e1838             32
  22. 22     02cfdf400370     7ffea051ec08             30
  23. 23     02cfdf400390     7ffea051ec08             32
  24. 24     02cfdf4003b0     7ffea051ec08             84
  25. 25     02cfdf400408     7ffea051ec08             98
  26. 26     02cfdf400470     7ffea051ec08             48
  27. 27     02cfdf4004a0     7ffea051ec08             54
  28. 28     02cfdf4004d8     7ffea051ec08             70
  29. 29     02cfdf400520     7ffea051ec08             70
  30. 30     02cfdf400568     7ffea051ec08            112
  31. 31     02cfdf4005d8     7ffea051ec08             38
  32. 32     02cfdf400600     7ffea051ec08             90
  33. 33     02cfdf400660     7ffea051ec08             42
  34. 34     02cfdf400690     7ffea051ec08            104
  35. 35     02cfdf4006f8     7ffea051ec08            130
  36. 36     02cfdf400780     7ffea051ec08            160
  37. 37     02cfdf400820     7ffea051ec08            124
  38. 38     02cfdf4008a0     7ffea051ec08             38
  39. 39     02cfdf4008c8     7ffea051ec08             24
  40. 40     02cfdf4008e0     7ffea051ec08             44
  41. 41     02cfdf400910     7ffea051ec08             24
  42. 42     02cfdf400928     7ffea05e9430             24
  43. 43     02cfdf400940     7ffea051ec08             26
  44. 44     02cfdf400960     7ffea051ec08             42
  45. 45     02cfdf400990     7ffea051ec08             40
  46. 46     02cfdf4009b8     7ffea051ec08             32
  47. 47     02cfdf4009d8     7ffea051ec08             32
  48. 48     02cfdf4009f8     7ffea051ec08             40
  49. 49     02cfdf400a20     7ffea051ec08             34
  50. 50
  51. 51 Statistics:
  52. 52           MT Count TotalSize Class Name
  53. 53 7ffea05e1838     1        32 System.Guid
  54. 54 7ffea046a318     1        40 System.RuntimeType
  55. 55 028f48d0c320     3        96 Free
  56. 56 7ffea051ec08    38     2,422 System.String
  57. 57 7ffea05e9430     4   855,096 System.Byte[]
  58. 58 Total 47 objects, 857,686 bytes
复制代码
                    因为,我们定义的对象大小最小就是 185000,所以,我们可以使用【!DumpHeap -min 185000】命令查看比 185000 大的对象。
  1. 1 0:000> !DumpHeap 028f4d800028     028f4d8d0ca8
  2. 2          Address               MT           Size
  3. 3     028f4d800028     028f48d0c320             32 Free
  4. 4     <strong>028f4d800048     7ffea05e9430        185,024(byte1 变量)</strong>
  5. 5     028f4d82d308     028f48d0c320             32 Free
  6. 6     <strong>028f4d82d328     7ffea05e9430        285,024 (byte2 变量)</strong>
  7. 7     028f4d872c88     028f48d0c320             32 Free
  8. 8     <strong>028f4d872ca8     7ffea05e9430        385,024 (byte3 变量)</strong>
  9. 9
  10. 10 Statistics:
  11. 11           MT Count TotalSize Class Name
  12. 12 028f48d0c320     3        96 Free
  13. 13 7ffea05e9430     3   855,072 System.Byte[]
  14. 14 Total 6 objects, 855,168 bytes
复制代码
                    我们【g】运行调试器。控制台应用程序输出“2、GC 已经触发,请查看托管堆中的 byte2”字样,调试器自动中断执行。
                    我们再次运行【!DumpHeap 028f4d800028 028f4d8d0ca8】命令,查看 LOH 的变化。
  1. 1 0:000> !DumpHeap -min 185000
  2. 2          Address               MT           Size
  3. 3     028f4d800048     7ffea05e9430        185,024
  4. 4     028f4d82d328     7ffea05e9430        285,024
  5. 5     028f4d872ca8     7ffea05e9430        385,024
  6. 6
  7. 7 Statistics:
  8. 8           MT Count TotalSize Class Name
  9. 9 7ffea05e9430     3   855,072 System.Byte[]
  10. 10 Total 3 objects, 855,072 bytes
复制代码
                    我们再次运行【g】调试器,控制台程序输出“3、已分配 byte4,查看是否 Free 块中”字样,调试器会自己中断执行。
                    我们再次运行【!DumpHeap 028f4d800028 028f4d8d0ca8】命令,查看 LOH 的变化。
  1. 1 0:000> !DumpHeap 028f4d800028     028f4d8d0ca8
  2. 2          Address               MT           Size
  3. 3     028f4d800028     028f48d0c320             32 Free
  4. 4     028f4d800048     7ffea05e9430        185,024
  5. 5     <strong>028f4d82d308     028f48d0c320        285,088 Free(byte2 变量已经释放)
  6. </strong> 6     028f4d872ca8     7ffea05e9430        385,024
  7. 7
  8. 8 Statistics:
  9. 9           MT Count TotalSize Class Name
  10. 10 028f48d0c320     2   285,120 Free
  11. 11 7ffea05e9430     2   570,048 System.Byte[]
  12. 12 Total 4 objects, 855,168 bytes
复制代码
                    红色标注的已经说明了问题,分配的 byte4 对象大小正好在 Free 块中,所以就把 byte4 直接存储了。

        3.2.6、固定
            A、基础知识
                垃圾收集器采用了一种紧缩技术来减少 GC 堆上的碎片。当 GC 要执行垃圾收集的操作时,空间碎片会进行合并形成一块更大的可用空间,在托管堆上的活跃的对象也要发生移动,对象的地址会发生变化,针对该对象的所有引用都会被更新,所有活跃的对象相邻存放,合并后的空间会紧跟在最后一个活跃对象的后边。如果针对移动过的对象的所有引用都包含在 CLR 中,那是没有问题的。

                如果 .NET 程序需要通过互用性服务(例如平台调用或者COM 互用性)在 CLR 范围之外工作,对象的移动就会产生问题。如果某个托管对象的引用被传递给一个底层的非托管 API ,那么当非托管的 API 正在读取或者写入的内存同时移动了对象,就会导致严重的问题。
      
                我们举例说明一下,先上一张图,然后具体说明。
                

                在上图中,在托管堆上起初包含了 5 个对象( A、B、C、D、E),对象 A 的地址 0x02000000,对象 C 的地址是 0x02000090。在某个特定时刻,通过平台调用来调用了一个异步的非托管的 API ,同时将对象 C 的地址(0x02000090)传递给 API。在调用这个非托管的异步 API 的时候发生了一次垃圾回收的操作,使得对象 A 和对象 B 被回收。此时,托管堆上出现了空闲对象造成的缝隙,因而 垃圾收集器会通过紧缩托管堆来解决这个问题,因此,对象 C 移动到了地址 0x02000000 处,此地址以前是对象 A 的。此外,还合并了这两块空闲内存,并将它们放在堆的末尾。在完成了垃圾收集后,之前进行的异步 API 调用决定写入到最初传递给它的地址(0x02000090),因为当初保存的是对象 C。此时,再看,已经是物是人非了,被写入的内存不再由对象 C 占用,就会导致系统产生问题,排查问题也挺麻烦的。
                如何解决在 GC 执行紧缩时仍能安全的调用非托管代码,有一种解决方案就是固定。是指将托管堆上的某个对象固定住,垃圾收集器回收内存时就不会移动该对象,直到解除对这个对象的固定为止。

                虽然通过固定对象的地址解决了在非托管代码调用期间的对象移动问题,但是也带来了另一个问题,内存碎片化,因为内存不能紧缩并合并导致而成。如果太托管堆上存在大量的固定对象,那么就会出现没有足够大而连续的空闲空间的情况,导致内存分配失败。在举例说明,如图:
                

                如上图所示,有数个空闲的小内存块与活跃的对象交错存放,如果执行一次垃圾收集,那么托管堆的内存布局将保持不变。由于活跃的对象都被固定住了,无法移动,垃圾收集器也就无法执行紧缩操作,又由于这些内存块不是相邻的,所以也不能合并。很容易导致内存分配失败。
                LOH 中的碎片情况怎么样?
                    我们知道 LOH 采用“标记清除”,而不是紧缩的垃圾收集方式,这就意味着 LOH 上的对象永远不会移动,那我们是否就可以不用管 LOH 对象,放心使用呢?不是的,如果没有固定住 LOH 上的对象,也是一种很危险的假设。因为在在不同的 CLR 版本中,这种假设是会变化的,为了防止发生不可预测的问题,该固定的还是固定使用吧。
              
                我们可以使用【!GCHandles】显示进程中的所有句柄。
            B、眼见为实
                调试源码:ExampleCore_5_6
                调试任务:如何固定对象和释放对象
                1)、NTSD 调试
                    编译项目,打开【Visual Studio 2022 Developer Command Prompt v17.9.6】命令行工具,输入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\bin\Debug\net8.0\ExampleCore_5_6.exe】打开调试器。
                    进入调试器,【g】直接运行程序,直到调试器输出如图:
                    

                    此时,内存已经分配,还没有执行垃圾回收,我们先看看当前进程中的所有句柄是否包含我们的数组对象。
                    按组合键【ctrl+c】组合键,进入调试器的中断模式,直接执行【!GCHandles】命令,查看所有的句柄信息。
  1. 1 0:000> !DumpHeap 028f4d800028     028f4d8d0ca8
  2. 2          Address               MT           Size
  3. 3     028f4d800028     028f48d0c320             32 Free
  4. 4     028f4d800048     7ffea05e9430        185,024
  5. 5     028f4d82d308     028f48d0c320             32 Free
  6. 6     <strong>028f4d82d328     7ffea05e9430        280,024</strong> <strong>(byte4变量)</strong>
  7. 7     028f4d871900     028f48d0c320          <strong>5,032 Free(多余出来的)
  8. </strong> 8     028f4d872ca8     7ffea05e9430        385,024
  9. 9
  10. 10 Statistics:
  11. 11           MT Count TotalSize Class Name
  12. 12 028f48d0c320     3     5,096 Free
  13. 13 7ffea05e9430     3   850,072 System.Byte[]
  14. 14 Total 6 objects, 855,168 bytes
复制代码
                    我们能看到 10 个 Strong 类型的句柄,4 个 Pinned 类型的句柄(包含我们定义的 3 个)和 6 个 Weak Short 类型的句柄。
                    我们切换到托管线程上下文中去看看,切换线程【~0s】。
  1. 1 0:002> !GCHandles
  2. 2           Handle Type                  Object     Size             Data Type
  3. 3 000001FA205A11B8 WeakShort   000001FA24C08FB8      400                  System.Diagnostics.Tracing.RuntimeEventSource
  4. 4 000001FA205A11C0 WeakShort   000001FA24C09378      184                  System.Diagnostics.Tracing.NativeRuntimeEventSource
  5. 5 000001FA205A11C8 WeakShort   000001FA24C09560       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  6. 6 000001FA205A11D0 WeakShort   000001FA24C094B0       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  7. 7 000001FA205A11D8 WeakShort   000001FA24C09298       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  8. 8 000001FA205A11E0 WeakShort   000001FA24C091E8       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  9. 9 000001FA205A1398 Strong      000001FA22402020     8184                  System.Object[]
  10. 10 000001FA205A13A0 Strong      000001FA24C092D8       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  11. 11 000001FA205A13A8 Strong      000001FA24C095A0       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  12. 12 000001FA205A13B0 Strong      000001FA24C094F0       88                  System.Diagnostics.Tracing.EtwEventProvider
  13. 13 000001FA205A13B8 Strong      000001FA24C09228       88                  System.Diagnostics.Tracing.EtwEventProvider
  14. 14 000001FA205A13C8 Strong      000001FA24C00188      128                  System.ExecutionEngineException
  15. 15 000001FA205A13D0 Strong      000001FA24C00108      128                  System.StackOverflowException
  16. 16 000001FA205A13D8 Strong      000001FA24C00088      128                  System.OutOfMemoryException
  17. 17 000001FA205A13E0 Strong      000001FA24C00028       96                  System.Int32[]
  18. 18 000001FA205A13E8 Strong      000001FA22400028     8184                  System.Object[]
  19. 19 <strong>000001FA205A15E0 Pinned      000001FA24C09E40      324                  System.SByte[](b3 变量,固定类型:<strong>Pinned</strong>)
  20. </strong>20 <strong>000001FA205A15E8 Pinned      000001FA24C09D60      224                  System.SByte[](b2 变量<strong>,固定类型:<strong>Pinned</strong></strong>)
  21. </strong>21<strong> 000001FA205A15F0 Pinned      000001FA24C09CE0      124                  System.SByte[](b1 变量<strong>,固定类型:<strong>Pinned</strong></strong>)
  22. </strong>22 000001FA205A15F8 Pinned      000001FA24C00208       24                  System.Object
  23. 23
  24. 24 Statistics:
  25. 25               MT    Count    TotalSize Class Name
  26. 26 00007ffca9d25fa8        1           24 System.Object
  27. 27 00007ffca9dd9df8        1           96 System.Int32[]
  28. 28 00007ffca9ea37b8        2          128 System.Diagnostics.Tracing.EventPipeEventProvider
  29. 29 00007ffca9e70c90        1          128 System.ExecutionEngineException
  30. 30 00007ffca9e70b90        1          128 System.StackOverflowException
  31. 31 00007ffca9e70a90        1          128 System.OutOfMemoryException
  32. 32 00007ffca9ea3a20        2          176 System.Diagnostics.Tracing.EtwEventProvider
  33. 33 00007ffca9ea85d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  34. 34 00007ffca9ea2b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  35. 35 00007ffca9ea2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  36. 36 <strong>00007ffca9eaab40        3          672 System.SByte[](这就是包含 3 个字节数组的类型)
  37. </strong>37 00007ffca9d2c4d8        2        16368 System.Object[]
  38. 38 Total 20 objects
  39. 39
  40. 40 Handles:
  41. 41     Strong Handles:       10
  42. 42     <strong>Pinned Handles:       4(3个类型是我们定义的)</strong>
  43. 43     Weak Short Handles:   6
复制代码
                    我们使用【!clrstack -a】命令查看一下托管调用栈。
  1. 1 0:002> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ffd`cf30d0c4 c3              ret
复制代码
                    红色标注的就是字节数组的变量(b1,b2,b3),蓝色的就是句柄变量(h1,h2,h3),都分配了空间。
                    我们可以使用【!do】或者【!DumpObj】命令查看一下数组变量。
  1. 1 0:000> !clrstack -a
  2. 2 OS Thread Id: 0x1d6c (0)
  3. 3         Child SP               IP Call Site
  4. 4 000000851CDAE548 00007ffdcf30d0c4 [InlinedCallFrame: 000000851cdae548]
  5. 5 000000851CDAE548 00007ffdba07787a [InlinedCallFrame: 000000851cdae548]
  6. 6 。。。。。。(省略了)
  7. 7 000000851CDAE6D0 00007FFCA9DF1B3E ExampleCore_5_6.Program.Run()
  8. 8     PARAMETERS:
  9. 9         this (0x000000851CDAE7A0) = 0x000001fa24c09628
  10. 10     LOCALS:
  11. 11         <strong>0x000000851CDAE788 = 0x000001fa24c09ce0(b1 变量)</strong>
  12. 12         <strong>0x000000851CDAE780 = 0x000001fa24c09d60(b2 变量)</strong>
  13. 13         <strong>0x000000851CDAE778 = 0x000001fa24c09e40(b3 变量)</strong>
  14. 14         <strong>0x000000851CDAE770 = 0x000001fa205a15f1(句柄变量 h1)</strong>
  15. 15         <strong>0x000000851CDAE768 = 0x000001fa205a15e9(句柄变量 h2)</strong>
  16. 16         <strong>0x000000851CDAE760 = 0x000001fa205a15e1(句柄变量 h3)</strong>
  17. 17
  18. 18 000000851CDAE7A0 00007FFCA9DF1988 ExampleCore_5_6.Program.Main(System.String[])
  19. 19     PARAMETERS:
  20. 20         args (0x000000851CDAE7F0) = 0x000001fa24c08e90
  21. 21     LOCALS:
  22. 22         0x000000851CDAE7D8 = 0x000001fa24c09628
复制代码
                    【g】继续运行调试器,直到调试器输出“Press any key to Free!”,说明完成了第一次垃圾回收。如图:
                    

                    按组合键【ctrl+c】进入中断模式,继续执行【!GCHandles】查看句柄详情。
  1. 1 0:000> !do 0x000001fa24c09ce0
  2. 2 Name:        System.SByte[]
  3. 3 MethodTable: 00007ffca9eaab40
  4. 4 EEClass:     00007ffca9eaaac0
  5. 5 Tracked Type: false
  6. 6 Size:        124(0x7c) bytes
  7. 7 Array:       Rank 1, Number of elements 100, Type SByte
  8. 8 Content:     ....................................................................................................
  9. 9 Fields:
  10. 10 None
复制代码
                    没有任何变化,垃圾也没回收句柄和数组的内存。
                    我们继续执行【g】,直到调试器输出“Press any key to GC2!”,此时已经完成释放句柄,按组合键【ctrl+c】进入中断模式,我们可以使用【!GCHandles】命令确认一下。
  1. 1 0:002> !GCHandles
  2. 2           Handle Type                  Object     Size             Data Type
  3. 3 000001FA205A11B8 WeakShort   000001FA24C08FB8      400                  System.Diagnostics.Tracing.RuntimeEventSource
  4. 4 000001FA205A11C0 WeakShort   000001FA24C09378      184                  System.Diagnostics.Tracing.NativeRuntimeEventSource
  5. 5 000001FA205A11C8 WeakShort   000001FA24C09560       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  6. 6 000001FA205A11D0 WeakShort   000001FA24C094B0       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  7. 7 000001FA205A11D8 WeakShort   000001FA24C09298       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  8. 8 000001FA205A11E0 WeakShort   000001FA24C091E8       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  9. 9 000001FA205A1398 Strong      000001FA22402020     8184                  System.Object[]
  10. 10 000001FA205A13A0 Strong      000001FA24C092D8       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  11. 11 000001FA205A13A8 Strong      000001FA24C095A0       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  12. 12 000001FA205A13B0 Strong      000001FA24C094F0       88                  System.Diagnostics.Tracing.EtwEventProvider
  13. 13 000001FA205A13B8 Strong      000001FA24C09228       88                  System.Diagnostics.Tracing.EtwEventProvider
  14. 14 000001FA205A13C8 Strong      000001FA24C00188      128                  System.ExecutionEngineException
  15. 15 000001FA205A13D0 Strong      000001FA24C00108      128                  System.StackOverflowException
  16. 16 000001FA205A13D8 Strong      000001FA24C00088      128                  System.OutOfMemoryException
  17. 17 000001FA205A13E0 Strong      000001FA24C00028       96                  System.Int32[]
  18. 18 000001FA205A13E8 Strong      000001FA22400028     8184                  System.Object[]
  19. <strong>19 000001FA205A15E0 Pinned      000001FA24C09E40      324                  System.SByte[]
  20. 20 000001FA205A15E8 Pinned      000001FA24C09D60      224                  System.SByte[]
  21. 21 000001FA205A15F0 Pinned      000001FA24C09CE0      124                  System.SByte[]
  22. </strong>22 000001FA205A15F8 Pinned      000001FA24C00208       24                  System.Object
  23. 23
  24. 24 Statistics:
  25. 25               MT    Count    TotalSize Class Name
  26. 26 00007ffca9d25fa8        1           24 System.Object
  27. 27 00007ffca9dd9df8        1           96 System.Int32[]
  28. 28 00007ffca9ea37b8        2          128 System.Diagnostics.Tracing.EventPipeEventProvider
  29. 29 00007ffca9e70c90        1          128 System.ExecutionEngineException
  30. 30 00007ffca9e70b90        1          128 System.StackOverflowException
  31. 31 00007ffca9e70a90        1          128 System.OutOfMemoryException
  32. 32 00007ffca9ea3a20        2          176 System.Diagnostics.Tracing.EtwEventProvider
  33. 33 00007ffca9ea85d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  34. 34 00007ffca9ea2b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  35. 35 00007ffca9ea2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  36. 36 <strong>00007ffca9eaab40        3          672 System.SByte[]
  37. </strong>37 00007ffca9d2c4d8        2        16368 System.Object[]
  38. 38 Total 20 objects
  39. 39
  40. 40 Handles:
  41. 41     Strong Handles:       10
  42. 42     <strong>Pinned Handles:       4</strong>
  43. 43     Weak Short Handles:   6
复制代码
                    我们可以切换到托管线程上下文中查看 Run 方法的栈帧来确定。
  1. 1 0:002> !GCHandles
  2. 2           Handle Type                  Object     Size             Data Type
  3. 3 000001FA205A11B8 WeakShort   000001FA24C08FB8      400                  System.Diagnostics.Tracing.RuntimeEventSource
  4. 4 000001FA205A11C0 WeakShort   000001FA24C09378      184                  System.Diagnostics.Tracing.NativeRuntimeEventSource
  5. 5 000001FA205A11C8 WeakShort   000001FA24C09560       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  6. 6 000001FA205A11D0 WeakShort   000001FA24C094B0       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  7. 7 000001FA205A11D8 WeakShort   000001FA24C09298       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  8. 8 000001FA205A11E0 WeakShort   000001FA24C091E8       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  9. 9 000001FA205A1398 Strong      000001FA22402020     8184                  System.Object[]
  10. 10 000001FA205A13A0 Strong      000001FA24C092D8       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  11. 11 000001FA205A13A8 Strong      000001FA24C095A0       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  12. 12 000001FA205A13B0 Strong      000001FA24C094F0       88                  System.Diagnostics.Tracing.EtwEventProvider
  13. 13 000001FA205A13B8 Strong      000001FA24C09228       88                  System.Diagnostics.Tracing.EtwEventProvider
  14. 14 000001FA205A13C8 Strong      000001FA24C00188      128                  System.ExecutionEngineException
  15. 15 000001FA205A13D0 Strong      000001FA24C00108      128                  System.StackOverflowException
  16. 16 000001FA205A13D8 Strong      000001FA24C00088      128                  System.OutOfMemoryException
  17. 17 000001FA205A13E0 Strong      000001FA24C00028       96                  System.Int32[]
  18. 18 000001FA205A13E8 Strong      000001FA22400028     8184                  System.Object[]
  19. 19 <strong>000001FA205A15E0 Pinned      000001FA24C09E40      324                  System.SByte[](b3 变量,固定类型:<strong>Pinned</strong>)
  20. </strong>20 <strong>000001FA205A15E8 Pinned      000001FA24C09D60      224                  System.SByte[](b2 变量<strong>,固定类型:<strong>Pinned</strong></strong>)
  21. </strong>21<strong> 000001FA205A15F0 Pinned      000001FA24C09CE0      124                  System.SByte[](b1 变量<strong>,固定类型:<strong>Pinned</strong></strong>)
  22. </strong>22 000001FA205A15F8 Pinned      000001FA24C00208       24                  System.Object
  23. 23
  24. 24 Statistics:
  25. 25               MT    Count    TotalSize Class Name
  26. 26 00007ffca9d25fa8        1           24 System.Object
  27. 27 00007ffca9dd9df8        1           96 System.Int32[]
  28. 28 00007ffca9ea37b8        2          128 System.Diagnostics.Tracing.EventPipeEventProvider
  29. 29 00007ffca9e70c90        1          128 System.ExecutionEngineException
  30. 30 00007ffca9e70b90        1          128 System.StackOverflowException
  31. 31 00007ffca9e70a90        1          128 System.OutOfMemoryException
  32. 32 00007ffca9ea3a20        2          176 System.Diagnostics.Tracing.EtwEventProvider
  33. 33 00007ffca9ea85d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  34. 34 00007ffca9ea2b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  35. 35 00007ffca9ea2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  36. 36 <strong>00007ffca9eaab40        3          672 System.SByte[](这就是包含 3 个字节数组的类型)
  37. </strong>37 00007ffca9d2c4d8        2        16368 System.Object[]
  38. 38 Total 20 objects
  39. 39
  40. 40 Handles:
  41. 41     Strong Handles:       10
  42. 42     <strong>Pinned Handles:       4(3个类型是我们定义的)</strong>
  43. 43     Weak Short Handles:   6
复制代码
                    使用【!clrstack -a】查看 Run 方法的栈帧。
  1. 1 0:002> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ffd`cf30d0c4 c3              ret
复制代码
                    红色标注的说明句柄变量已经释放,数组变量还没有回收。
                    【g】继续运行,直到调试器输出“Press any key to Exit!”,此时,第二次垃圾回收已经完成,剩下的数组变量也应该被回收了。按组合键【ctrl+c】进入中断模式,我们直接切换线程,执行【!clrstack -a】命令就可以了。
  1. 1 0:002> !GCHandles
  2. 2           Handle Type                  Object     Size             Data Type
  3. 3 000001FA205A11B8 WeakShort   000001FA24C08FB8      400                  System.Diagnostics.Tracing.RuntimeEventSource
  4. 4 000001FA205A11C0 WeakShort   000001FA24C09378      184                  System.Diagnostics.Tracing.NativeRuntimeEventSource
  5. 5 000001FA205A11C8 WeakShort   000001FA24C09560       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  6. 6 000001FA205A11D0 WeakShort   000001FA24C094B0       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  7. 7 000001FA205A11D8 WeakShort   000001FA24C09298       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  8. 8 000001FA205A11E0 WeakShort   000001FA24C091E8       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  9. 9 000001FA205A1398 Strong      000001FA22402020     8184                  System.Object[]
  10. 10 000001FA205A13A0 Strong      000001FA24C092D8       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  11. 11 000001FA205A13A8 Strong      000001FA24C095A0       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  12. 12 000001FA205A13B0 Strong      000001FA24C094F0       88                  System.Diagnostics.Tracing.EtwEventProvider
  13. 13 000001FA205A13B8 Strong      000001FA24C09228       88                  System.Diagnostics.Tracing.EtwEventProvider
  14. 14 000001FA205A13C8 Strong      000001FA24C00188      128                  System.ExecutionEngineException
  15. 15 000001FA205A13D0 Strong      000001FA24C00108      128                  System.StackOverflowException
  16. 16 000001FA205A13D8 Strong      000001FA24C00088      128                  System.OutOfMemoryException
  17. 17 000001FA205A13E0 Strong      000001FA24C00028       96                  System.Int32[]
  18. 18 000001FA205A13E8 Strong      000001FA22400028     8184                  System.Object[]
  19. 19 <strong>000001FA205A15E0 Pinned      000001FA24C09E40      324                  System.SByte[](b3 变量,固定类型:<strong>Pinned</strong>)
  20. </strong>20 <strong>000001FA205A15E8 Pinned      000001FA24C09D60      224                  System.SByte[](b2 变量<strong>,固定类型:<strong>Pinned</strong></strong>)
  21. </strong>21<strong> 000001FA205A15F0 Pinned      000001FA24C09CE0      124                  System.SByte[](b1 变量<strong>,固定类型:<strong>Pinned</strong></strong>)
  22. </strong>22 000001FA205A15F8 Pinned      000001FA24C00208       24                  System.Object
  23. 23
  24. 24 Statistics:
  25. 25               MT    Count    TotalSize Class Name
  26. 26 00007ffca9d25fa8        1           24 System.Object
  27. 27 00007ffca9dd9df8        1           96 System.Int32[]
  28. 28 00007ffca9ea37b8        2          128 System.Diagnostics.Tracing.EventPipeEventProvider
  29. 29 00007ffca9e70c90        1          128 System.ExecutionEngineException
  30. 30 00007ffca9e70b90        1          128 System.StackOverflowException
  31. 31 00007ffca9e70a90        1          128 System.OutOfMemoryException
  32. 32 00007ffca9ea3a20        2          176 System.Diagnostics.Tracing.EtwEventProvider
  33. 33 00007ffca9ea85d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  34. 34 00007ffca9ea2b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  35. 35 00007ffca9ea2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  36. 36 <strong>00007ffca9eaab40        3          672 System.SByte[](这就是包含 3 个字节数组的类型)
  37. </strong>37 00007ffca9d2c4d8        2        16368 System.Object[]
  38. 38 Total 20 objects
  39. 39
  40. 40 Handles:
  41. 41     Strong Handles:       10
  42. 42     <strong>Pinned Handles:       4(3个类型是我们定义的)</strong>
  43. 43     Weak Short Handles:   6
复制代码
                    执行【!clrstack -a】命令。
  1. 1 0:002> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ffd`cf30d0c4 c3              ret
复制代码
                    从输出中就可以看到,我们并没有看到 Run 方法的栈帧,只有 ExampleCore_5_6.Program.Main 栈帧了,说明已经回收了,验证了我们的说法。

                2)、Windbg Preview 调试
                    编译项目,打开【Windbg Preview】调试器,依次点击【文件】---【Launch executable】,加载我们的项目文件:ExampleCore_5_6.exe,进入到调试器。
                    进入到调试器,我们可以直接输入【g】命令,继续运行调试器,我们的控制台会输出“Press any key to Alloc And Pinned!”,如果此时,我们查找变量是一无所获的,因为还没有分配内存。我们继续在控制台程序中按任意键继续运行程序,直到程序输出“Press any key to GC1!”,效果如图:
                    

                    此时,内存已经分配,我们回到调试器,点击【break】按钮,中断调试器的执行,开始我们的调试。
                    我们直接输入【!GCHandles】命令,查看当前进程中所有的句柄。
  1. 1 0:000> !clrstack -a
  2. 2 OS Thread Id: 0x1d6c (0)
  3. 3         Child SP               IP Call Site
  4. 4 000000851CDAE648 00007ffdcf30d0c4 [InlinedCallFrame: 000000851cdae648] Interop+Kernel32.<ReadConsoleInput>g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  5. 5 000000851CDAE648 00007ffca9df1e25 [InlinedCallFrame: 000000851cdae648] Interop+Kernel32.<ReadConsoleInput>g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  6. 6 。。。。。。(省略了)
  7. 7 000000851CDAE7A0 00007FFCA9DF19A4 ExampleCore_5_6.Program.Main(System.String[])
  8. 8     PARAMETERS:
  9. 9         args (0x000000851CDAE7F0) = 0x000001fa24c08e90
  10. 10     LOCALS:
  11. 11         0x000000851CDAE7D8 = 0x000001fa24c09628
复制代码
                    我们看到有 10 个 Strong 类型的句柄,4 个 Pinned 类型的句柄,6 个 Weak Short 类型的句柄。红色标注的就是我们声明的 b1,b2,b3 3个变量。
                    我们切换到托管线上的上下文中,去线程调用栈中看看能不能找到 b1、b2 和 b3 这三个变量。
  1. 1 0:006> !GCHandles
  2. 2           Handle Type                  Object     Size             Data Type
  3. 3 00000197A1C311B8 WeakShort   00000197a6008fb8      400                  System.Diagnostics.Tracing.RuntimeEventSource
  4. 4 00000197A1C311C0 WeakShort   00000197a6009378      184                  System.Diagnostics.Tracing.NativeRuntimeEventSource
  5. 5 00000197A1C311C8 WeakShort   00000197a6009560       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  6. 6 00000197A1C311D0 WeakShort   00000197a60094b0       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  7. 7 00000197A1C311D8 WeakShort   00000197a6009298       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  8. 8 00000197A1C311E0 WeakShort   00000197a60091e8       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  9. 9 00000197A1C31398 Strong      00000197a3802020     8184                  System.Object[]
  10. 10 00000197A1C313A0 Strong      00000197a60092d8       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  11. 11 00000197A1C313A8 Strong      00000197a60095a0       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  12. 12 00000197A1C313B0 Strong      00000197a60094f0       88                  System.Diagnostics.Tracing.EtwEventProvider
  13. 13 00000197A1C313B8 Strong      00000197a6009228       88                  System.Diagnostics.Tracing.EtwEventProvider
  14. 14 00000197A1C313C8 Strong      00000197a6000188      128                  System.ExecutionEngineException
  15. 15 00000197A1C313D0 Strong      00000197a6000108      128                  System.StackOverflowException
  16. 16 00000197A1C313D8 Strong      00000197a6000088      128                  System.OutOfMemoryException
  17. 17 00000197A1C313E0 Strong      00000197a6000028       96                  System.Int32[]
  18. 18 00000197A1C313E8 Strong      00000197a3800028     8184                  System.Object[]
  19. 19 <strong>00000197A1C315E0 Pinned      00000197a6009e40      324                  System.SByte[](Run()方法中的变量 b3,固定类型:Pinned)
  20. </strong>20 <strong>00000197A1C315E8 Pinned      00000197a6009d60      224                  System.SByte[](Run()方法中的变量 b2,固定类型:Pinned)
  21. </strong>21 <strong>00000197A1C315F0 Pinned      00000197a6009ce0      124                  System.SByte[](Run()方法中的变量 b1,固定类型:Pinned)
  22. </strong>22 00000197A1C315F8 Pinned      00000197a6000208       24                  System.Object
  23. 23
  24. 24 Statistics:
  25. 25               MT    Count    TotalSize Class Name
  26. 26 00007ffc8f275fa8        1           24 System.Object
  27. 27 00007ffc8f329df8        1           96 System.Int32[]
  28. 28 00007ffc8f3f37b8        2          128 System.Diagnostics.Tracing.EventPipeEventProvider
  29. 29 00007ffc8f3c0c90        1          128 System.ExecutionEngineException
  30. 30 00007ffc8f3c0b90        1          128 System.StackOverflowException
  31. 31 00007ffc8f3c0a90        1          128 System.OutOfMemoryException
  32. 32 00007ffc8f3f3a20        2          176 System.Diagnostics.Tracing.EtwEventProvider
  33. 33 00007ffc8f3f85d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  34. 34 00007ffc8f3f2b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  35. 35 00007ffc8f3f2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  36. 36 <strong>00007ffc8f3fab40        3          672 System.SByte[](这里也是我们 3 个变量的统计信息,672就是 124+224+324 的和)
  37. </strong>37 00007ffc8f27c4d8        2        16368 System.Object[]
  38. 38 Total 20 objects
  39. 39
  40. 40 Handles:
  41. 41     Strong Handles:       10
  42. 42     Pinned Handles:       4
  43. 43     Weak Short Handles:   6
复制代码
                    继续使用【!ClrStack -a】命令显示线程调用栈的所有参数和局部变量。
  1. 1 0:006> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ffd`cf30d0c4 c3              ret
复制代码
                    我们主要关注 Run 方法的调用栈,标红的就是我们声明的 3 个局部变量,我们可以使用【!do】命令依次查看。
  1. 1 0:000> !clrstack -a
  2. 2 OS Thread Id: 0x598 (0)
  3. 3         Child SP               IP Call Site
  4. 4 00000087DC9CE3C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce3c8]
  5. 5 00000087DC9CE3C8 00007ffd49df787a [InlinedCallFrame: 00000087dc9ce3c8]
  6. 6 00000087DC9CE3A0 00007ffd49df787a Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  7. 7     PARAMETERS:
  8. 8         hConsoleInput = <no data>
  9. 9         buffer = <no data>
  10. 10         numInputRecords_UseOne = <no data>
  11. 11         numEventsRead = <no data>
  12. 12     LOCALS:
  13. 13         <no data>
  14. 14         <no data>
  15. 15         <no data>
  16. 16         <no data>
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20
  21. 21 00000087DC9CE490 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  22. 22     PARAMETERS:
  23. 23         intercept (<CLR reg>) = 0x0000000000000000
  24. 24     LOCALS:
  25. 25         <no data>
  26. 26         <no data>
  27. 27         <no data>
  28. 28         <no data>
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         0x00000087DC9CE4D0 = 0x00000197a6009c98
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         <no data>
  37. 37         <no data>
  38. 38
  39. 39 <strong>00000087DC9CE550 00007ffc8f341b3e ExampleCore_5_6.Program.Run</strong>() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 34]
  40. 40     PARAMETERS:
  41. 41         this (0x00000087DC9CE620) = 0x00000197a6009628
  42. 42     LOCALS:
  43. 43         0x00000087DC9CE608 = <strong>0x00000197a6009ce0(这就是 b1 变量)</strong>
  44. 44         0x00000087DC9CE600 = <strong>0x00000197a6009d60(这就是 b2 变量)</strong>
  45. 45         0x00000087DC9CE5F8 = <strong>0x00000197a6009e40(这就是 b3 变量)</strong>
  46. 46         0x00000087DC9CE5F0 = 0x00000197a1c315f1
  47. 47         0x00000087DC9CE5E8 = 0x00000197a1c315e9
  48. 48         0x00000087DC9CE5E0 = 0x00000197a1c315e1
  49. 49
  50. 50 00000087DC9CE620 00007ffc8f341988 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 10]
  51. 51     PARAMETERS:
  52. 52         args (0x00000087DC9CE670) = 0x00000197a6008e90
  53. 53     LOCALS:
  54. 54         0x00000087DC9CE658 = 0x00000197a6009628
复制代码
                    我们继续【g】运行调试器,控制台程序输出“Press any key to Free!”,回收内存,但是还没有取消固定,回到调试器,点击【break】按钮,中断调试器的执行。
                    我们先执行【!GCHandles】命令,看看句柄还在吗?
  1. 1 0:000> !do 0x00000197a6009ce0
  2. 2 Name:        System.SByte[]
  3. 3 MethodTable: 00007ffc8f3fab40
  4. 4 EEClass:     00007ffc8f3faac0
  5. 5 Tracked Type: false
  6. 6 Size:        124(0x7c) bytes
  7. 7 Array:       Rank 1, Number of elements 100, Type SByte (Print Array)
  8. 8 Content:     ....................................................................................................
  9. 9 Fields:
  10. 10 None
  11. 11
  12. 12 0:000> !do 00000197a6009d60
  13. 13 Name:        System.SByte[]
  14. 14 MethodTable: 00007ffc8f3fab40
  15. 15 EEClass:     00007ffc8f3faac0
  16. 16 Tracked Type: false
  17. 17 Size:        224(0xe0) bytes
  18. 18 Array:       Rank 1, Number of elements 200, Type SByte (Print Array)
  19. 19 Content:     ................................................................................................................................
  20. 20 Fields:
  21. 21 None
  22. 22
  23. 23 0:000> !do 0x00000197a6009e40
  24. 24 Name:        System.SByte[]
  25. 25 MethodTable: 00007ffc8f3fab40
  26. 26 EEClass:     00007ffc8f3faac0
  27. 27 Tracked Type: false
  28. 28 Size:        324(0x144) bytes
  29. 29 Array:       Rank 1, Number of elements 300, Type SByte (Print Array)
  30. 30 Content:     ................................................................................................................................
  31. 31 Fields:
  32. 32 None
复制代码
                    句柄还在,这是正确的,我们还没有释放句柄。我们再次切换到托管线程上下文,看看有没有释放内存(已经执行垃圾回收了)。
  1. 1 0:001> !GCHandles
  2. 2           Handle Type                  Object     Size             Data Type
  3. 3 00000197A1C311B8 WeakShort   00000197a6008fb8      400                  System.Diagnostics.Tracing.RuntimeEventSource
  4. 4 00000197A1C311C0 WeakShort   00000197a6009378      184                  System.Diagnostics.Tracing.NativeRuntimeEventSource
  5. 5 00000197A1C311C8 WeakShort   00000197a6009560       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  6. 6 00000197A1C311D0 WeakShort   00000197a60094b0       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  7. 7 00000197A1C311D8 WeakShort   00000197a6009298       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  8. 8 00000197A1C311E0 WeakShort   00000197a60091e8       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  9. 9 00000197A1C31398 Strong      00000197a3802020     8184                  System.Object[]
  10. 10 00000197A1C313A0 Strong      00000197a60092d8       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  11. 11 00000197A1C313A8 Strong      00000197a60095a0       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  12. 12 00000197A1C313B0 Strong      00000197a60094f0       88                  System.Diagnostics.Tracing.EtwEventProvider
  13. 13 00000197A1C313B8 Strong      00000197a6009228       88                  System.Diagnostics.Tracing.EtwEventProvider
  14. 14 00000197A1C313C8 Strong      00000197a6000188      128                  System.ExecutionEngineException
  15. 15 00000197A1C313D0 Strong      00000197a6000108      128                  System.StackOverflowException
  16. 16 00000197A1C313D8 Strong      00000197a6000088      128                  System.OutOfMemoryException
  17. 17 00000197A1C313E0 Strong      00000197a6000028       96                  System.Int32[]
  18. 18 00000197A1C313E8 Strong      00000197a3800028     8184                  System.Object[]
  19. 19 <strong>00000197A1C315E0 Pinned      00000197a6009e40      324                  System.SByte[]
  20. </strong>20 <strong>00000197A1C315E8 Pinned      00000197a6009d60      224                  System.SByte[]
  21. </strong>21 <strong>00000197A1C315F0 Pinned      00000197a6009ce0      124                  System.SByte[]
  22. </strong>22 00000197A1C315F8 Pinned      00000197a6000208       24                  System.Object
  23. 23
  24. 24 Statistics:
  25. 25               MT    Count    TotalSize Class Name
  26. 26 00007ffc8f275fa8        1           24 System.Object
  27. 27 00007ffc8f329df8        1           96 System.Int32[]
  28. 28 00007ffc8f3f37b8        2          128 System.Diagnostics.Tracing.EventPipeEventProvider
  29. 29 00007ffc8f3c0c90        1          128 System.ExecutionEngineException
  30. 30 00007ffc8f3c0b90        1          128 System.StackOverflowException
  31. 31 00007ffc8f3c0a90        1          128 System.OutOfMemoryException
  32. 32 00007ffc8f3f3a20        2          176 System.Diagnostics.Tracing.EtwEventProvider
  33. 33 00007ffc8f3f85d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  34. 34 00007ffc8f3f2b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  35. 35 00007ffc8f3f2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  36. 36 <strong>00007ffc8f3fab40        3          672 System.SByte[]
  37. </strong>37 00007ffc8f27c4d8        2        16368 System.Object[]
  38. 38 Total 20 objects
  39. 39
  40. 40 Handles:
  41. 41     Strong Handles:       10
  42. 42     Pinned Handles:       4
  43. 43     Weak Short Handles:   6
复制代码
                  我们从输出结果中可以看到,对象依然存在,因为该对象被固定住了。
                  我们继续执行【g】,控制台程序输出“Press any key to GC2!”,说明已经释放句柄,将要执行第二次垃圾回收。回到调试器,点击【break】按钮,中断调试器的执行,开始调试。
                  继续执行【!GCHandles】命令,查看句柄的情况。
  1. 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ffd`cf30d0c4 c3              ret
  4. 4
  5. 5 0:000> !ClrStack -a
  6. 6 OS Thread Id: 0x598 (0)
  7. 7         Child SP               IP Call Site
  8. 8 00000087DC9CE3F8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce3f8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  9. 9 00000087DC9CE3F8 00007ffc8f341d05 [InlinedCallFrame: 00000087dc9ce3f8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  10. 10 。。。。。。(省略了)
  11. 11 00000087DC9CE550 00007ffc8f341b64 ExampleCore_5_6.Program.Run() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 39]
  12. 12     PARAMETERS:
  13. 13         this (0x00000087DC9CE620) = 0x00000197a6009628
  14. 14     LOCALS:
  15. 15         0x00000087DC9CE608 = 0x00000197a6009ce0
  16. 16         0x00000087DC9CE600 = 0x00000197a6009d60
  17. 17         0x00000087DC9CE5F8 = 0x00000197a6009e40
  18. 18         0x00000087DC9CE5F0 = 0x00000197a1c315f1
  19. 19         0x00000087DC9CE5E8 = 0x00000197a1c315e9
  20. 20         0x00000087DC9CE5E0 = 0x00000197a1c315e1
  21. 21
  22. 22 00000087DC9CE620 00007ffc8f341988 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 10]
  23. 23     PARAMETERS:
  24. 24         args (0x00000087DC9CE670) = 0x00000197a6008e90
  25. 25     LOCALS:
  26. 26         0x00000087DC9CE658 = 0x00000197a6009628
  27. 27
  28. 28
  29. 29 0:000> !DumpObj /d 00000197a6009ce0
  30. 30 Name:        System.SByte[]
  31. 31 MethodTable: 00007ffc8f3fab40
  32. 32 EEClass:     00007ffc8f3faac0
  33. 33 Tracked Type: false
  34. 34 Size:        124(0x7c) bytes
  35. 35 Array:       Rank 1, Number of elements 100, Type SByte (Print Array)
  36. 36 Content:     ....................................................................................................
  37. 37 Fields:
  38. 38 None
复制代码
                  真没有了,Pinned 类型的句柄以前是 4 个,现在是 1 个,少了 3 个。切换到托管线程上下文,执行命令【!clrstack -a】看看调用栈,也发生了变化。
  1. 1 0:001> !GCHandles
  2. 2           Handle Type                  Object     Size             Data Type
  3. 3 00000197A1C311B8 WeakShort   00000197a6008fb8      400                  System.Diagnostics.Tracing.RuntimeEventSource
  4. 4 00000197A1C311C0 WeakShort   00000197a6009378      184                  System.Diagnostics.Tracing.NativeRuntimeEventSource
  5. 5 00000197A1C311C8 WeakShort   00000197a6009560       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  6. 6 00000197A1C311D0 WeakShort   00000197a60094b0       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  7. 7 00000197A1C311D8 WeakShort   00000197a6009298       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  8. 8 00000197A1C311E0 WeakShort   00000197a60091e8       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  9. 9 00000197A1C31398 Strong      00000197a3802020     8184                  System.Object[]
  10. 10 00000197A1C313A0 Strong      00000197a60092d8       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  11. 11 00000197A1C313A8 Strong      00000197a60095a0       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  12. 12 00000197A1C313B0 Strong      00000197a60094f0       88                  System.Diagnostics.Tracing.EtwEventProvider
  13. 13 00000197A1C313B8 Strong      00000197a6009228       88                  System.Diagnostics.Tracing.EtwEventProvider
  14. 14 00000197A1C313C8 Strong      00000197a6000188      128                  System.ExecutionEngineException
  15. 15 00000197A1C313D0 Strong      00000197a6000108      128                  System.StackOverflowException
  16. 16 00000197A1C313D8 Strong      00000197a6000088      128                  System.OutOfMemoryException
  17. 17 00000197A1C313E0 Strong      00000197a6000028       96                  System.Int32[]
  18. 18 00000197A1C313E8 Strong      00000197a3800028     8184                  System.Object[]
  19. 19 00000197A1C315F8 Pinned      00000197a6000208       24                  System.Object
  20. 20
  21. 21 Statistics:
  22. 22               MT    Count    TotalSize Class Name
  23. 23 00007ffc8f275fa8        1           24 System.Object
  24. 24 00007ffc8f329df8        1           96 System.Int32[]
  25. 25 00007ffc8f3f37b8        2          128 System.Diagnostics.Tracing.EventPipeEventProvider
  26. 26 00007ffc8f3c0c90        1          128 System.ExecutionEngineException
  27. 27 00007ffc8f3c0b90        1          128 System.StackOverflowException
  28. 28 00007ffc8f3c0a90        1          128 System.OutOfMemoryException
  29. 29 00007ffc8f3f3a20        2          176 System.Diagnostics.Tracing.EtwEventProvider
  30. 30 00007ffc8f3f85d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  31. 31 00007ffc8f3f2b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  32. 32 00007ffc8f3f2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  33. 33 00007ffc8f27c4d8        2        16368 System.Object[]
  34. 34 Total 17 objects
  35. 35
  36. 36 Handles:
  37. 37     Strong Handles:       10
  38. 38     Pinned Handles:       1
  39. 39     Weak Short Handles:   6
复制代码
                  红色标注的就是发生变化的。3 个数组变量依然存在,3 个句柄变量已经释放了。
                  我们继续【g】执行调试器,控制台程序输出“Press any key to Exit!”,此时,已经成功执行第二垃圾回收,我们回到调试器,点击【break】按钮,进入到中断模式。此时,不用执行【!GCHandles】命令,句柄已经释放了。我们直接去托管线程上下文,查看调用栈,确认 3 个数组变量已经被回收了。
  1. 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ffd`cf30d0c4 c3              ret
  4. 4
  5. 5 0:000> !clrstack -a
  6. 6 OS Thread Id: 0x598 (0)
  7. 7         Child SP               IP Call Site
  8. 8 00000087DC9CE3F8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce3f8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  9. 9 00000087DC9CE3F8 00007ffc8f341d05 [InlinedCallFrame: 00000087dc9ce3f8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  10. 10 。。。。。。(省略了)
  11. 11 00000087DC9CE550 00007ffc8f341ba4 ExampleCore_5_6.Program.Run() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 46]
  12. 12     PARAMETERS:
  13. 13         this (0x00000087DC9CE620) = 0x00000197a6009628
  14. 14     LOCALS:
  15. 15         <strong>0x00000087DC9CE608</strong> <strong>= 0x00000197a6009ce0(此时,b1 还在托管堆上)</strong>
  16. 16         <strong>0x00000087DC9CE600 = 0x00000197a6009d60(此时,b2 还在托管堆上)</strong>
  17. 17         <strong>0x00000087DC9CE5F8 = 0x00000197a6009e40(此时,b3 还在托管堆上)</strong>
  18. 18         <strong>0x00000087DC9CE5F0 = 0x0000000000000000(句柄 h1已经释放了,这是变化的)</strong>
  19. 19         <strong>0x00000087DC9CE5E8 = 0x0000000000000000(句柄 h2已经释放了,这是变化的)</strong>
  20. 20         <strong>0x00000087DC9CE5E0 = 0x0000000000000000(句柄 h3已经释放了,这是变化的)</strong>
  21. 21
  22. 22 00000087DC9CE620 00007ffc8f341988 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 10]
  23. 23     PARAMETERS:
  24. 24         args (0x00000087DC9CE670) = 0x00000197a6008e90
  25. 25     LOCALS:
  26. 26         0x00000087DC9CE658 = 0x00000197a6009628
复制代码
                  此时,我们看到,Run 方法的栈帧都没有了,说明内存被回收了。

        3.2.7、垃圾收集模式
            垃圾收集模式公有 3 种:非并发工作站、并发工作站、服务器。

            服务器模式:为每个处理器创建一个堆和一个 GC 线程,垃圾收集操作都是通过处理器上专门的 GC 线程来执行的。

            非并发工作站模式:在整个垃圾收集过程中会挂起所有的托管线程,只有在垃圾收集操作完成后,才会恢复进程中所有的托管线程的执行。在不需要快速相应的情况下,这种方式还好。在需要响应速度的情况下,比如:GUI程序,也就是 WinForm、WPF等就不合适了,半天没反应,客户是不答应的。

            并发工作站模式:在整个垃圾收集的过程中并不会一直挂起托管线程,而是会定期醒来,并且在执行一些必要的工作后再重新休眠。这增加了程序的响应速度,但是会使垃圾收集操作略微变慢。

    3.3、调试托管堆的破坏问题
        A、基础知识
            堆破坏 是一种违背了堆完整性的错误,它会导致程序出现奇怪的行为。想要查找问题也是十分困难,因为在托管堆被破坏后表现出的行为各不相同。我们期望的是,在出现堆破坏的问题时,程序就立刻出现崩溃,这样就尽可能的保证发生崩溃的位置与发生破坏的位置相近,就不需要通过大量的栈回溯找出最初发生破坏的位置。
            虽然造成堆破坏的原因有多种,但是一个非常常见的原因就是:没有正确的管理程序中的内存。例如:释放内存后再次使用内存,悬空指针,缓冲区溢出等,都可能导致堆破坏。然而,CLR 通过高效的管理内存解决了很多问题。例如:一块内存释放后,将无法再次使用。缓冲区溢出也会被识别出来作为一个异常。想要这些起作用,必须保证代码运行在托管环境中才可以。
            
            当我们通过互用性服务调用非托管 API 时,传递给非托管 API 的数据是不受 CLR 保护的。所以说,托管代码与非托管代码的交互是在托管环境中导致堆破坏的最主要原因之一。当然,在没有使用任何非托管代码的情况下也可能出现堆破坏的情况,但是,这样的情况极少,通常说 CLR 本身存在一个错误。            

            当托管堆被破坏了,我们可以使用【!VerifyHeap】命令来验证堆的完整性。该命令会遍历整个托管堆,验证每个对象,并且报告验证过程的结果。

            如果还是在使用 .NET Framework 平台,那么使用 gcUnmanagedToManaged(包含 gcManagedToUnmanaged) 这个 MDA 就会很方便,但是,如果在跨平台的 NET 版本中就不可以了,切记。

        B、眼见为实
            调试源码:ExampleCore_5_7 和 ExampleCore_5_8(C++)
            调试任务:通过 MDA 排查有关堆破坏的问题。
            C++ 的项目需要说明一下,项目的属性【配置类型】是"动态库(.dll)",输出目录:..\ExampleCore_5_7\bin\Debug\net8.0\。
            在这个项目里还有一个 mda 的配置文件,ExampleCore_5_7.exe.mda.config。
            想要启动 MDA,需要提前做一些准备,我在”基础知识“中,贴出了网址,如果不熟悉的大家可以自己恶补。我的操作过程是通过三步完成的,第一步,配置环境变量,第二步:配置项目的 MDA 配置文件,第三步就可以执行测试了。
            第一步:在我的电脑里配置环境变量(COMPLUS_MDA=1,启动 MDA.)。
            

            第二步:我为我的程序配置了 mda 配置文件,文件名:Example_13_1_1.exe.mda.config。配置详情如下:
  1. 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ffd`cf30d0c4 c3              ret
  4. 4
  5. 5 0:000> !ClrStack -a
  6. 6 OS Thread Id: 0x598 (0)
  7. 7         Child SP               IP Call Site
  8. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  9. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  10. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  11. 11     PARAMETERS:
  12. 12         hConsoleInput = <no data>
  13. 13         buffer = <no data>
  14. 14         numInputRecords_UseOne = <no data>
  15. 15         numEventsRead = <no data>
  16. 16     LOCALS:
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20         <no data>
  21. 21         <no data>
  22. 22         <no data>
  23. 23         <no data>
  24. 24
  25. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  26. 26     PARAMETERS:
  27. 27         intercept (<CLR reg>) = 0x0000000000000000
  28. 28     LOCALS:
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         <no data>
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  37. 37         <no data>
  38. 38         <no data>
  39. 39         <no data>
  40. 40         <no data>
  41. 41         <no data>
  42. 42
  43. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  44. 44     PARAMETERS:
  45. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  46. 46     LOCALS:
  47. 47         0x00000087DC9CE658 = 0x00000197a6009628
复制代码
            第三步:我没有选择调试工具,直接运行 exe,并没有看到任何错误,结果输出了(说明 MDA 在 NET 平台无效,只是针对 .NET Framework 平台)。效果如图:
            

            我们发现程序并没有出现错误。我们通过调试器试试。
            1)、NTSD 调试
                编译项目,打开【Visual Studio 2022 Developer Command Prompt v17.9.6】命令行工具,输入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_7\bin\Debug\net8.0\ExampleCore_5_7.exe】打开调试器。
                进入调试器后,我们直接【g】运行调试器,直到调试器输出如图:
                

                按组合键【ctrl+c】进入中断模式,从输出结果中已经知道输出是有错误的,并且,我们调用了非托管的 API,所以上来第一步我们先验证一下托管堆有没有问题,执行命令【!VerifyHeap】。
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <mdaConfig>
  3.     <assistants>
  4.         <gcManagedToUnmanaged/>
  5.         <gcUnmanagedToManaged/>
  6.     </assistants>
  7. </mdaConfig>
复制代码
                我们一看就知道有错误了,那么多 Error 。虽然知道有了错误,我尝试了一些方法,都没办法继续下去了。我就到此为止了,Windbg Preview 测试的还是更好点,这也是我推荐在工作中使用 Windbg Preview 做调试的原因。

            2)、Windbg Preview 调试
                我们编译项目,打开【Windbg Preview】调试器,依次点击【文件】---【Launch Executable】,加载我们的项目文件:ExampleCore_5_7.exe,进入调试器后。我们直接【g】运行调试器,直到我们的控制台程序输出结果为止。
                效果如图:
                

                此时,我们回到调试器中,点击【break】按钮,中断调试器,开始调试。
                我们输入【!VerifyHeap】命令,来验证一下托管堆是否有效。
  1. 1 0:002> !VerifyHeap2 Segment          Object           Failure 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ffd`cf30d0c4 c3              ret
  4. 4
  5. 5 0:000> !ClrStack -a
  6. 6 OS Thread Id: 0x598 (0)
  7. 7         Child SP               IP Call Site
  8. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  9. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  10. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  11. 11     PARAMETERS:
  12. 12         hConsoleInput = <no data>
  13. 13         buffer = <no data>
  14. 14         numInputRecords_UseOne = <no data>
  15. 15         numEventsRead = <no data>
  16. 16     LOCALS:
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20         <no data>
  21. 21         <no data>
  22. 22         <no data>
  23. 23         <no data>
  24. 24
  25. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  26. 26     PARAMETERS:
  27. 27         intercept (<CLR reg>) = 0x0000000000000000
  28. 28     LOCALS:
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         <no data>
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  37. 37         <no data>
  38. 38         <no data>
  39. 39         <no data>
  40. 40         <no data>
  41. 41         <no data>
  42. 42
  43. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  44. 44     PARAMETERS:
  45. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  46. 46     LOCALS:
  47. 47         0x00000087DC9CE658 = 0x00000197a6009628  Reason3 02543cbaec40     021428c02020     InvalidObjectReference           Object 21428c02020 has a bad member at offset 10: 2142b4096c84 02543cbaf320     02142b409648     InvalidMethodTable               Object 2142b409648 has an invalid method table 610061006100615 6 229 objects verified, 2 errors.
复制代码
                我们看到了,虽然程序没崩溃,其实我们的托管堆是有问题的。位于地址 2142b409648 处的对象的方法表是无效的。我们可以很容易验证这一点,即将这个地址上的内容通过【dp】命令显示出来。
  1. 1 0:002> !VerifyHeap
  2. 2 Segment          Object           Failure                          Reason
  3. 3 02543cbaec40     021428c02020     InvalidObjectReference           Object 21428c02020 has a bad member at offset 10: 2142b4096c8
  4. 4 02543cbaf320     02142b409648     InvalidMethodTable               Object 2142b409648 has an invalid method table 61006100610061
  5. 5
  6. 6 229 objects verified, 2 errors.
复制代码
                此时,我们就知道了堆被破坏了。
                我们可以针对地址:2142b409648 使用【!listnearobj 2142b409648】命令列出该地址附近的对象,看看具体情况。
  1. 1 0:002> !listnearobj 2142b4096482 [b]Before:              02142b409628 30 (0x1e) 1 0:001> ~0s
  2. 2 ntdll!NtDeviceIoControlFile+0x14:
  3. 3 00007ffd`cf30d0c4 c3              ret
  4. 4
  5. 5 0:000> !ClrStack -a
  6. 6 OS Thread Id: 0x598 (0)
  7. 7         Child SP               IP Call Site
  8. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  9. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  10. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  11. 11     PARAMETERS:
  12. 12         hConsoleInput = <no data>
  13. 13         buffer = <no data>
  14. 14         numInputRecords_UseOne = <no data>
  15. 15         numEventsRead = <no data>
  16. 16     LOCALS:
  17. 17         <no data>
  18. 18         <no data>
  19. 19         <no data>
  20. 20         <no data>
  21. 21         <no data>
  22. 22         <no data>
  23. 23         <no data>
  24. 24
  25. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  26. 26     PARAMETERS:
  27. 27         intercept (<CLR reg>) = 0x0000000000000000
  28. 28     LOCALS:
  29. 29         <no data>
  30. 30         <no data>
  31. 31         <no data>
  32. 32         <no data>
  33. 33         <no data>
  34. 34         <no data>
  35. 35         <no data>
  36. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  37. 37         <no data>
  38. 38         <no data>
  39. 39         <no data>
  40. 40         <no data>
  41. 41         <no data>
  42. 42
  43. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  44. 44     PARAMETERS:
  45. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  46. 46     LOCALS:
  47. 47         0x00000087DC9CE658 = 0x00000197a6009628System.Char[](这个就是我们声明的 char 数组)[/b]3 Current:             02142b409648 1 0:001> ~0s
  48. 2 ntdll!NtDeviceIoControlFile+0x14:
  49. 3 00007ffd`cf30d0c4 c3              ret
  50. 4
  51. 5 0:000> !ClrStack -a
  52. 6 OS Thread Id: 0x598 (0)
  53. 7         Child SP               IP Call Site
  54. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  55. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  56. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  57. 11     PARAMETERS:
  58. 12         hConsoleInput = <no data>
  59. 13         buffer = <no data>
  60. 14         numInputRecords_UseOne = <no data>
  61. 15         numEventsRead = <no data>
  62. 16     LOCALS:
  63. 17         <no data>
  64. 18         <no data>
  65. 19         <no data>
  66. 20         <no data>
  67. 21         <no data>
  68. 22         <no data>
  69. 23         <no data>
  70. 24
  71. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  72. 26     PARAMETERS:
  73. 27         intercept (<CLR reg>) = 0x0000000000000000
  74. 28     LOCALS:
  75. 29         <no data>
  76. 30         <no data>
  77. 31         <no data>
  78. 32         <no data>
  79. 33         <no data>
  80. 34         <no data>
  81. 35         <no data>
  82. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  83. 37         <no data>
  84. 38         <no data>
  85. 39         <no data>
  86. 40         <no data>
  87. 41         <no data>
  88. 42
  89. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  90. 44     PARAMETERS:
  91. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  92. 46     LOCALS:
  93. 47         0x00000087DC9CE658 = 0x00000197a6009628          Unknown4 Error Detected: Object 2142b409648 has an invalid method table 61006100610061 [verify heap]5 Next:                02142b4096f8 40 (0x28) 1 0:001> ~0s
  94. 2 ntdll!NtDeviceIoControlFile+0x14:
  95. 3 00007ffd`cf30d0c4 c3              ret
  96. 4
  97. 5 0:000> !ClrStack -a
  98. 6 OS Thread Id: 0x598 (0)
  99. 7         Child SP               IP Call Site
  100. 8 00000087DC9CE4C8 00007ffdcf30d0c4 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  101. 9 00000087DC9CE4C8 00007ffc8f341e25 [InlinedCallFrame: 00000087dc9ce4c8] Interop+Kernel32.g____PInvoke|45_0(IntPtr, INPUT_RECORD*, Int32, Int32*)
  102. 10 00000087DC9CE4A0 00007ffc8f341e25 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 470]
  103. 11     PARAMETERS:
  104. 12         hConsoleInput = <no data>
  105. 13         buffer = <no data>
  106. 14         numInputRecords_UseOne = <no data>
  107. 15         numEventsRead = <no data>
  108. 16     LOCALS:
  109. 17         <no data>
  110. 18         <no data>
  111. 19         <no data>
  112. 20         <no data>
  113. 21         <no data>
  114. 22         <no data>
  115. 23         <no data>
  116. 24
  117. 25 00000087DC9CE560 00007ffd49dfaa0a System.ConsolePal.ReadKey(Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 334]
  118. 26     PARAMETERS:
  119. 27         intercept (<CLR reg>) = 0x0000000000000000
  120. 28     LOCALS:
  121. 29         <no data>
  122. 30         <no data>
  123. 31         <no data>
  124. 32         <no data>
  125. 33         <no data>
  126. 34         <no data>
  127. 35         <no data>
  128. 36         0x00000087DC9CE5A0 = 0x00000197a6009c98
  129. 37         <no data>
  130. 38         <no data>
  131. 39         <no data>
  132. 40         <no data>
  133. 41         <no data>
  134. 42
  135. 43 00000087DC9CE620 00007ffc8f3419a4 ExampleCore_5_6.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_6\Program.cs @ 13]
  136. 44     PARAMETERS:
  137. 45         args (0x00000087DC9CE670) = 0x00000197a6008e90
  138. 46     LOCALS:
  139. 47         0x00000087DC9CE658 = 0x00000197a6009628System.Buffers.SharedArrayPool6 Expected to find next object at 2142b409648, instead found it at 2142b4096f8.7 Heap local consistency not confirmed.
复制代码
                我们可以使用【!do 02142b409628】或者【!DumpObj 02142b409628】命令来确认我们说的对不对。
  1. 1 0:002> !listnearobj 2142b409648
  2. 2 <strong>Before:              02142b409628 30 (0x1e)                        System.Char[](这个就是我们声明的 char 数组)
  3. </strong>3 Current:             02142b409648                                  Unknown
  4. 4 Error Detected: Object 2142b409648 has an invalid method table 61006100610061 [verify heap]
  5. 5 Next:                02142b4096f8 40 (0x28)                        System.Buffers.SharedArrayPool<System.Char>
  6. 6 Expected to find next object at 2142b409648, instead found it at 2142b4096f8.
  7. 7 Heap local consistency not confirmed.
复制代码
                内容是 3 个 a,以前是 a、b、c 三个元素,说明数据被修改了。我们也可以使用【dp 02142b409628】命令直接输出结果。
  1. 1 0:002> !do 02142b409628
  2. 2 Name:        System.Char[]
  3. 3 MethodTable: 00007ffaf3ff9438
  4. 4 EEClass:     00007ffaf3ff93b8
  5. 5 Tracked Type: false
  6. 6 Size:        30(0x1e) bytes
  7. 7 Array:       Rank 1, Number of elements 3, Type Char (Print Array)
  8. 8 <strong>Content:     aaa
  9. </strong> 9 Fields:
  10. 10 None
复制代码
                00007ffa`f3ff9438 是方法表,00000000`00000003 是元素的个数:3个,0061 就是 十进制 97(英文字母 a)。
                我们可以针对使用【!DumpArray 02142b409628】命令输出这个数组元素,并使用【!DumpVC】命令输出每个元素值。
  1. 1 0:002> dp 02142b409628
  2. 2 00000214`2b409628  <strong>00007ffa`f3ff9438</strong> <strong>00000000`00000003
  3. </strong>3 00000214`2b409638  00610061`00610061 00610061`00610061
  4. 4 00000214`2b409648  00610061`00610061 00610061`00610061
  5. 5 00000214`2b409658  00610061`00610061 00610061`00610061
  6. 6 00000214`2b409668  00610061`00610061 00610061`00610061
  7. 7 00000214`2b409678  00610061`00610061 00610061`00610061
  8. 8 00000214`2b409688  00610061`00610061 00610061`00610061
  9. 9 00000214`2b409698  00610061`00610061 00610061`00610061
复制代码
                我们知道了字符数组有问题,就能推断错误在哪里。

    3.4、调试托管堆的碎片问题
        A、基础知识
            在托管堆上,当空闲内存块和被占用内存块交错存放,就会出现内存碎片的问题,我们的应用程序也会出现各种问题,通常表现为抛出 OutOfMemoryException 异常。我们如何确定有堆碎片问题呢?有一个标准可以参考,我们可以使用【空闲块总大小与托管堆总大小的比值】,如果空闲块占据了大部分堆空间,那么堆碎片可能会是一个问题。
            我们还有一个问题需要关注,堆碎片发生在哪个代。在第 0 代中通常没有碎片,因为 CLR 堆管理器可以使用任何空闲的内存块来进行分配。然而,在第 1 代和第 2代中,使用空闲块唯一的方式就是将对象提升到各自的代中。由于第 1 代是临时内存段的一部分,并且只有一个临时内存段,因此,在调试堆碎片的问题时,通常需要分析第 2 代的内存空间。
            当我们使用句柄“固定”一个对象的时候,过多的或者过久的“固定”是造成托管堆上出现碎片的最常见原因之一。如果需要固定对象,那么我们必须保证固定的时间较短,从而不对垃圾收集器造成太多的影响。

            如果在 Windows 虚拟内存管理器管理的内存中产生了碎片,CLR 不会通过增加堆容量(增加新的内存段)来满足分配需求,我们可以使用【address】命令系统虚拟内存状态的详细信息。

            有哪些工具可以监视进程中内存的使用量呢?有多种选择,最基本的方式就是使用【任务管理器】,可以按下【ctrl+shift+esc】组合键就可以打开【任务管理器】,如图:
            

            【任务管理器】只能大略的查看内存使用情况,如果我们想知道消耗的内存是位于非托管堆上还是托管堆上?是在堆上还是在其他什么地方,【任务管理器】就不能胜任了。此时,我们就应该使用【Windows 性能监视器】,它可以用来分析系统的整个状态或者是每个进程的状态。它使用了不同的数据源,例如:性能计数器,跟踪日志以及配置信息等,但是,性能监视器是用于分析 .NET Framework 应用程序的最易用的工具,跨平台是不适合的。
            以下标红的内容是针对 .NET Framework 平台的,我记录一下而已,如果想关注 .NET 8.0 此处可以略过。
            如果我们想运行【性能监视器】,可以在【运行框】中输入【perfmon】命令,就可以打开【性能监视器】。效果如图:
            

            性能监视器如图:
            

            我们可以点击左侧的【性能监视器】,在右侧通常显示 Processor Time 计数器,如果要添加计数器,可以点击右键,选择【添加计数器(D)】菜单,打开添加计数器的菜单,按着自己需求操作就可以了。效果如图:
            

            【添加计数器】由两部分组成,第一步部分就是【可用计数器】选项,它包含一个 计数器种类 的下拉列表,以及可用对象的实例,并且性能计数器将在这些实例上收集和现实数据。右侧面板会列出已经被添加的所有性能计数器。
            我们必须清楚的知道每种性能计数器的用途,才知道如何选择,具体性能计数器的用途如图:
            .NET CLR 数据(.NET CLR Data):关于数据(例如 SOL)性能的运行时统计信息
            .NET CLR 异常(.NET CLR Exceptions):关于 CLR 异常处理的运行时统计信息,例如所抛出的异常数量
            .NET CLR 互用性(.NET CLR Interop):关于互用性服务的运行时统计,例如列集操作的次数
            .NET CLR 即时编译器(.NET CLR Jit):关于即时编译器的运行时统计,例如被即时编译器编译的方法数量
            .NET CLR 加载过程(.NET CLR Loading):关于CLR类/程序集加载器的运行时统计,例如加载器堆中的字节总数
            .NET CLR 锁与线程(.NET CLR LocksAndThreads):关于锁和线程的运行时统计,例如锁的竞争率
            .NET CLR 内存(.NET CLR Memory):关于托管堆和垃圾收集器的运行时统计,例如每一代中收集操作的次数
            .NET CLR 网络(.NET CLRE Networking):关于网络的运行时统计,例如已发送和已接收的数据报
            .NET CLR 远程操作(.NET CLR Remoting):关于远程行为的运行时统计,例如每秒钟发生的远程调用次数
            .NET CLR 安全(.NET CLR Security):关于安全性的运行时统计,例如运行时检查的总次数

        B、眼见为实
            B1、调试源码:ExampleCore_5_9
               调试任务:如何找到堆碎片问题并且分析发生问题的原因。
              1)、NTSD 调试
                  编译项目,打开【Visual Studio 2022 Developer Command Prompt v17.9.6】命令行工具,输入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_9\bin\Debug\net8.0\ExampleCore_5_9.exe】打开调试器。
                  进入到调试器后,直接【g】运行调试器,我们的控制台程序输出“”字样,让我们输入分配内存的大小,我输入 50000 字节,回车。控制台继续输出“”字样,让我们输入分配内存的最大值,我输入 1000 MB(也就是 1 G MB)字节,回车。此时,我们的控制台程序输出“Press any key to GC & promo to gen1”字样。效果如图:
                  

                  按组合键【ctrl+c】进入中断模式,开始我们的调试。
                  我们先看看托管堆上的统计情况,执行【!DumpHeap -stat】命令。
  1. 1 0:002> !DumpArray 02142b409628
  2. 2 Name:        System.Char[]
  3. 3 MethodTable: 00007ffaf3ff9438
  4. 4 EEClass:     00007ffaf3ff93b8
  5. 5 Size:        30(0x1e) bytes
  6. 6 Array:       Rank 1, Number of elements 3, Type Char
  7. 7 Element Methodtable: 00007ffaf3ebb538
  8. 8 [0] <strong>000002142b409638(0 索引元素地址)
  9. </strong> 9 [1] <strong>000002142b40963a<strong>(1 索引元素地址)</strong>
  10. </strong>10 [2] <strong>000002142b40963c<strong>(2 索引元素地址)</strong>
  11. </strong>11
  12. 12 0:002> !DumpVC /d 00007ffaf3ebb538 000002142b409638
  13. 13 Name:        System.Char
  14. 14 MethodTable: 00007ffaf3ebb538
  15. 15 EEClass:     00007ffaf3ea8360
  16. 16 Size:        24(0x18) bytes
  17. 17 File:        C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll
  18. 18 Fields:
  19. 19               MT    Field   Offset                 Type VT     Attr            Value Name
  20. 20 00007ffaf3ebb538  40003b2        0          System.Char  1 instance               <strong>61</strong> m_value
  21. 21
  22. 22 0:002> !DumpVC /d 00007ffaf3ebb538 000002142b40963a
  23. 23 Name:        System.Char
  24. 24 MethodTable: 00007ffaf3ebb538
  25. 25 EEClass:     00007ffaf3ea8360
  26. 26 Size:        24(0x18) bytes
  27. 27 File:        C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll
  28. 28 Fields:
  29. 29               MT    Field   Offset                 Type VT     Attr            Value Name
  30. 30 00007ffaf3ebb538  40003b2        0          System.Char  1 instance               <strong>61</strong> m_value
  31. 31
  32. 32 0:002> !DumpVC /d 00007ffaf3ebb538 000002142b40963c
  33. 33 Name:        System.Char
  34. 34 MethodTable: 00007ffaf3ebb538
  35. 35 EEClass:     00007ffaf3ea8360
  36. 36 Size:        24(0x18) bytes
  37. 37 File:        C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll
  38. 38 Fields:
  39. 39               MT    Field   Offset                 Type VT     Attr            Value Name
  40. 40 00007ffaf3ebb538  40003b2        0          System.Char  1 instance               <strong>61</strong> m_value
复制代码
                  红色标注的已经说明的很清楚了,由于我们在关注对碎片,所以主要看标注【Free】的数据。我们可以看到内存空闲块有 19695 个,所在空间的大小是 1365104 字节,也就是 1.36 MB。有了空闲内存块的大小了,我们在看看 GC 堆总的大小是多少,执行【!eeheap -gc】命令。
  1. 1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes. -stat
  34. 2 Statistics:
  35. 3               MT    Count    TotalSize Class Name
  36. 4 00007ff8f3036dd0        1           24 System.IO.SyncTextReader
  37. 5 00007ff8f301f1c0        1           24 System.Threading.Tasks.Task+<>c
  38. 6 00007ff8f301a898        1           24 System.IO.Stream+NullStream
  39. 7 00007ff8f2fe0100        1           24 ExampleCore_5_9.Program
  40. 8 。。。。。。(省略了)
  41. 9 00007ff8f2fe2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  42. 10 00007ff8f303c978        2          912 System.Globalization.CultureData
  43. 11 00007ff8f2fbfa88       17          976 System.String[]
  44. 12 00007ff8f2f19df8        8         3432 System.Int32[]
  45. 13 00007ff8f2e6c4d8        3        16544 System.Object[]
  46. 14 00007ff8f301f920        3        33356 System.Char[]
  47. 15 00007ff8f2f1ec08      187        39732 System.String
  48. 16 <strong>00007ff8f2fe9820        1       160024 System.Runtime.InteropServices.GCHandle[](我们声明的句柄数组:pinnedHandles)
  49. </strong>17 <strong>00007ff8f2fe9610        2       160048 System.Byte[][](我们声明的字节数组:nonPinned 和 pinned)
  50. </strong>18 <strong>0000029481a7bed0    19695      1365104      Free(这是当前的内存空闲块)
  51. </strong>19 00007ff8f2fe9410    20003   1000484178 System.Byte[]
  52. 20 Total 39996 objects
复制代码
 
                  我们看到 GC 堆分配了 1 GB 左右的空间,空闲块总大小是 1.36 MB,也就是堆碎片在系统的 0.1,这个比例不是很大,可以继续运行。其实,我们在使用【!eeheap -gc】命令的输出中,能看到第 2 代有很多的内存段,说明分配了很多新的内存。由于我们正在分配一块非常大的内存,因此,临时内存段会很快被填满,并开始创建新的第 2 代内存段。
                  我们可以使用【!DumpHeap -type Free】命令或者【!dumpheap -mt 0000029481a7bed0】命令来找出堆上所有的空闲内存块。
  1. 1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7000028
  4. 4 generation 1 starts at 0x00000294D6000028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 <strong>generation 0:(第 0 代)
  9. </strong> 9 000002D49767D1E0  00000294D7000028  00000294D7000028  00000294D7321000  0x0(0)  0x320fd8(3280856)
  10. 10 <strong>generation 1:(第 1 代)
  11. </strong>11 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  12. 12 000002D49767CFD0  00000294D6400028  00000294D660D690  00000294D6800000  0x20d668(2152040)  0x3fffd8(4194264)
  13. 13 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  14. 14 000002D49767D130  00000294D6C00028  00000294D6E0D690  00000294D6E11000  0x20d668(2152040)  0x210fd8(2166744)
  15. 15 <strong>generation 2:(第 2 代)
  16. </strong>16 0000029481B3EA70  000002D518170008  000002D518171D38  000002D518180000  0x1d30(7472)  0xfff8(65528)
  17. 17 000002D49766F270  0000029485C00028  0000029485CE5E90  0000029485FF6000  0xe5e68(941672)  0x3f5fd8(4153304)
  18. 18 000002D49766F320  0000029486000028  0000029486178C28  00000294863F9000  0x178c00(1543168)  0x3f8fd8(4165592)
  19. 19 000002D49766F950  0000029488400028  00000294887F6290  0000029488800000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49766FA00  0000029488800028  0000029488A0D690  0000029488A4E000  0x20d668(2152040)  0x24dfd8(2416600)
  21. 21 。。。。。。(太多了,省略了)
  22. 22 00000294D4E11000  0x20d668(2152040)  0x210fd8(2166744)
  23. 23 000002D49767CC60  00000294D5000028  00000294D53F6290  00000294D5400000  0x3f6268(4153960)  0x3fffd8(4194264)
  24. 24 000002D49767CD10  00000294D5400028  00000294D560D690  00000294D5800000  0x20d668(2152040)  0x3fffd8(4194264)
  25. 25 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  26. 26 000002D49767CE70  00000294D5C00028  00000294D5E0D690  00000294D5E11000  0x20d668(2152040)  0x210fd8(2166744)
  27. 27 Large object heap starts at 0x0000000000000000
  28. 28          segment             begin         allocated         committed    allocated size    committed size
  29. 29 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  30. 30 Pinned object heap starts at 0x0000000000000000
  31. 31 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  32. 32 Total Allocated Size:              Size: 0x3b8bc920 (999016736) bytes.
  33. 33 Total Committed Size:              Size: 0x41ba5df8 (1102732792) bytes.
  34. 34 ------------------------------
  35. 35 <strong>GC Allocated Heap Size:    Size: 0x3b8bc920 (999016736) bytes.
  36. </strong>36 GC Committed Heap Size:    Size: 0x41ba5df8 (1102732792) bytes.
复制代码
                  另外【!dumpheap -mt】命令的结果类似。
  1. 1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes. -type Free
  34. 2 00000294cdd62590 0000029481a7bed0       24 Free
  35. 3 00000294cdd6e910 0000029481a7bed0       24 Free
  36. 4 00000294cdd7ac90 0000029481a7bed0       24 Free
  37. 5 00000294cdd87010 0000029481a7bed0       24 Free
  38. 6 00000294cdd93390 0000029481a7bed0       24 Free
  39. 7 00000294cdd9f710 0000029481a7bed0       24 Free
  40. 8 。。。。。。。(省略了)
  41. 9 00000294d2de8c10 0000029481a7bed0       24 Free
  42. 10 00000294d2df4f90 0000029481a7bed0       24 Free
  43. 11 00000294d2e01310 0000029481a7bed0       24 Free
  44. 12 00000294d300c390 0000029481a7bed0       24 Free
  45. 13 00000294d3018710 0000029481a7bed0       24 Free
  46. 14 00000294d3024a90 0000029481a7bed0       24 Free
  47. 15 00000294d3030e10 0000029481a7bed0       24 Free
  48. 16 00000294d303d190 0000029481a7bed0       24 Free
  49. 17 。。。。。。(省略了)
  50. 18 00000294d5a93d10 0000029481a7bed0       24 Free
  51. 19 00000294d5aa0090 0000029481a7bed0       24 Free
  52. 20 00000294d5aac410 0000029481a7bed0       24 Free
  53. 21 00000294d5ab8790 0000029481a7bed0       24 Free
  54. 22 00000294d5ac4b10 0000029481a7bed0       24 Free
  55. 23 00000294d5ad0e90 0000029481a7bed0       24 Free
  56. 24 00000294d5add210 0000029481a7bed0       24 Free
  57. 25 00000294d5ae9590 0000029481a7bed0       24 Free
  58. 26 00000294d5af5910 0000029481a7bed0       24 Free
  59. 27 。。。。。。(省略了)
  60. 28 00000294d5daba90 0000029481a7bed0       24 Free
  61. 29 00000294d5db7e10 0000029481a7bed0       24 Free
  62. 30 00000294d5dc4190 0000029481a7bed0       24 Free
  63. 31 00000294d5dd0510 0000029481a7bed0       24 Free
  64. 32 00000294d5ddc890 0000029481a7bed0       24 Free
  65. 33 00000294d5de8c10 0000029481a7bed0       24 Free
  66. 34 00000294d5df4f90 0000029481a7bed0       24 Free
  67. 35 00000294d5e01310 0000029481a7bed0       24 Free
  68. 36 0000029486400028 0000029481a7bed0       32 Free
  69. 37
  70. 38 Statistics:
  71. 39               MT    Count    TotalSize Class Name
  72. 40 0000029481a7bed0    19695      1365104      Free
  73. 41 Total 19695 objects
  74. 42 0:001>
复制代码
                  我们【g】继续测试,恢复程序的执行,如果提示,就按任意键继续,直到控制台程序输出“Press any key to Exit”字样为止。
                  效果如图:
                  

                  此时,我们点击【ctrl+c】组合键进入中断模式,输入命令【!DumpHeap -stat】统计一下托管堆的情况。
  1. 1 0:001> !dumpheap -mt 0000029481a7bed0
  2. 2 00000294bca87990 0000029481a7bed0       24 Free
  3. 3 00000294bca93d10 0000029481a7bed0       24 Free
  4. 4 00000294bcaa0090 0000029481a7bed0       24 Free
  5. 5 00000294bcaac410 0000029481a7bed0       24 Free
  6. 6 00000294bcab8790 0000029481a7bed0       24 Free
  7. 7 00000294bcac4b10 0000029481a7bed0       24 Free
  8. 8 00000294bcad0e90 0000029481a7bed0       24 Free
  9. 9 00000294bcadd210 0000029481a7bed0       24 Free
  10. 10 00000294bcae9590 0000029481a7bed0       24 Free
  11. 11 00000294bcaf5910 0000029481a7bed0       24 Free
  12. 12 00000294bcb01c90 0000029481a7bed0       24 Free
  13. 13 。。。。。。
  14. 14 00000294c7b1a390 0000029481a7bed0       24 Free
  15. 15 00000294c7b26710 0000029481a7bed0       24 Free
  16. 16 00000294c7b32a90 0000029481a7bed0       24 Free
  17. 17 00000294c7b3ee10 0000029481a7bed0       24 Free
  18. 18 00000294c7b4b190 0000029481a7bed0       24 Free
  19. 19 00000294c7b57510 0000029481a7bed0       24 Free
  20. 20 00000294c7b63890 0000029481a7bed0       24 Free
  21. 21 00000294c7b6fc10 0000029481a7bed0       24 Free
  22. 22 00000294c7b7bf90 0000029481a7bed0       24 Free
  23. 23 00000294c7b88310 0000029481a7bed0       24 Free
  24. 24 。。。。。。
  25. 25 00000294d026f290 0000029481a7bed0       24 Free
  26. 26 00000294d027b610 0000029481a7bed0       24 Free
  27. 27 00000294d0287990 0000029481a7bed0       24 Free
  28. 28 00000294d0293d10 0000029481a7bed0       24 Free
  29. 29 00000294d02a0090 0000029481a7bed0       24 Free
  30. 30 00000294d02ac410 0000029481a7bed0       24 Free
  31. 31 00000294d02b8790 0000029481a7bed0       24 Free
  32. 32 00000294d02c4b10 0000029481a7bed0       24 Free
  33. 33 00000294d02d0e90 0000029481a7bed0       24 Free
  34. 34 00000294d02dd210 0000029481a7bed0       24 Free
  35. 35 00000294d02e9590 0000029481a7bed0       24 Free
  36. 36 。。。。。。
  37. 37 00000294d5daba90 0000029481a7bed0       24 Free
  38. 38 00000294d5db7e10 0000029481a7bed0       24 Free
  39. 39 00000294d5dc4190 0000029481a7bed0       24 Free
  40. 40 00000294d5dd0510 0000029481a7bed0       24 Free
  41. 41 00000294d5ddc890 0000029481a7bed0       24 Free
  42. 42 00000294d5de8c10 0000029481a7bed0       24 Free
  43. 43 00000294d5df4f90 0000029481a7bed0       24 Free
  44. 44 00000294d5e01310 0000029481a7bed0       24 Free
  45. 45 0000029486400028 0000029481a7bed0       32 Free
  46. 46
  47. 47 Statistics:
  48. 48               MT    Count    TotalSize Class Name
  49. 49 0000029481a7bed0    19695      1365104      Free
  50. 50 Total 19695 objects
  51. 51 0:001>
复制代码
                  我们这次看到了内存空闲块发生了很大的变化,数量变化不大,以前是 19695,现在是 9846,数量变少了。内存空间变大了,以前是 1.36 MB,现在是 492 MB。
                  我们在把 GC 堆分配的内存输出出来,查看一下。执行命令【!eeheap -gc】。
  1. 1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes. -stat
  34. 2 Statistics:
  35. 3               MT    Count    TotalSize Class Name
  36. 4 00007ff8f3036dd0        1           24 System.IO.SyncTextReader
  37. 5 00007ff8f301f1c0        1           24 System.Threading.Tasks.Task+<>c
  38. 6 00007ff8f301a898        1           24 System.IO.Stream+NullStream
  39. 7 00007ff8f2fe0100        1           24 ExampleCore_5_9.Program
  40. 8 00007ff8f2fbca50        1           24 System.OrdinalIgnoreCaseComparer
  41. 9 。。。。。。(省略了)
  42. 10 00007ff8f2fe2208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  43. 11 00007ff8f303c978        2          912 System.Globalization.CultureData
  44. 12 00007ff8f2fbfa88       17          976 System.String[]
  45. 13 00007ff8f2f19df8        8         3432 System.Int32[]
  46. 14 00007ff8f2e6c4d8        3        16544 System.Object[]
  47. 15 00007ff8f301f920        3        33356 System.Char[]
  48. 16 00007ff8f2f1ec08      187        39714 System.String
  49. 17 <strong>00007ff8f2fe9820        1       160024 System.Runtime.InteropServices.GCHandle[](我们声明的句柄数组:pinnedHandles,没什么变化)
  50. </strong>18 <strong>00007ff8f2fe9610        2       160048 System.Byte[][](我们声明的字节数组:nonPinned 和 pinned,也没变化)
  51. </strong>19 <strong>0000029481a7bed0     9846    492996800      Free(内存空闲块,变化了,空间增大了,以前是 1.36 MB,492 MB)
  52. </strong>20 00007ff8f2fe9410    10004    500294202 System.Byte[]
  53. 21 Total 20148 objects
复制代码
                  GC 堆的大小是 1 GB 左右,空闲内存块占据将近 500 MB 大小,说明现在堆的碎片率是 50%了,可以使用【!DumpHeap】命令确认这一点。
  1. 1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes.
复制代码
  1. 0:001> !DumpHeap
复制代码
                  我们主要关注标红的,它们是交错分布的,一个空闲对象,一个有对象,出现这种情况,一般来说,就是对象被固定了,不能移动,GC 无法执行紧缩和合并操作,我们可以使用【!GCHandles】命令,查看一下句柄的使用情况。
  1.   1 00000294b3987028 00007ff8f2fe9410    50024
  2.   2 00000294b3993390 0000029481a7bed0    50072 Free
  3.   3 00000294b399f728 00007ff8f2fe9410    50024
  4.   4 00000294b39aba90 0000029481a7bed0    50072 Free
  5.   5 00000294b39b7e28 00007ff8f2fe9410    50024
  6.   6 00000294b39c4190 0000029481a7bed0    50072 Free
  7.   7 00000294b39d0528 00007ff8f2fe9410    50024
  8.   8 00000294b39dc890 0000029481a7bed0    50072 Free
  9.   9 00000294b39e8c28 00007ff8f2fe9410    50024
  10. 10 00000294b39f4f90 0000029481a7bed0    50072 Free
  11. 11 00000294b3a01328 00007ff8f2fe9410    50024
  12. 12 00000294b3a0d690 0000029481a7bed0    50072 Free
  13. 13 00000294b3a19a28 00007ff8f2fe9410    50024
  14. 14 00000294b3a25d90 0000029481a7bed0    50072 Free
  15. 15 00000294b3a32128 00007ff8f2fe9410    50024
  16. 16 00000294b3a3e490 0000029481a7bed0    50072 Free
  17. 17 00000294b3a4a828 00007ff8f2fe9410    50024
  18. 18 00000294b3a56b90 0000029481a7bed0    50072 Free
  19. 19 00000294b3a62f28 00007ff8f2fe9410    50024
  20. 20 00000294b3a6f290 0000029481a7bed0    50072 Free
  21. 21 00000294b3a7b628 00007ff8f2fe9410    50024
  22. 22 00000294b3a87990 0000029481a7bed0    50072 Free
  23. 23 00000294b3a93d28 00007ff8f2fe9410    50024
  24. 24 00000294b3aa0090 0000029481a7bed0    50072 Free
  25. 25 00000294b3aac428 00007ff8f2fe9410    50024
  26. 26 00000294b3ab8790 0000029481a7bed0    50072 Free
  27. 27 00000294b3ac4b28 00007ff8f2fe9410    50024
  28. 28 00000294b3ad0e90 0000029481a7bed0    50072 Free
  29. 29 00000294b3add228 00007ff8f2fe9410    50024
  30. 30 00000294b3ae9590 0000029481a7bed0    50072 Free
  31. 31 00000294b3af5928 00007ff8f2fe9410    50024
  32. 32 00000294b3b01c90 0000029481a7bed0    50072 Free
  33. 33 00000294b3b0e028 00007ff8f2fe9410    50024
  34. 34 00000294b3b1a390 0000029481a7bed0    50072 Free
  35. 35 00000294b3b26728 00007ff8f2fe9410    50024
  36. 36 00000294b3b32a90 0000029481a7bed0    50072 Free
  37. 37 00000294b3b3ee28 00007ff8f2fe9410    50024
  38. 38 00000294b3b4b190 0000029481a7bed0    50072 Free
  39. 39 00000294b3b57528 00007ff8f2fe9410    50024
  40. 40 00000294b3b63890 0000029481a7bed0    50072 Free
  41. 41 00000294b3b6fc28 00007ff8f2fe9410    50024
  42. 42 。。。。。。(省略了)
  43. 43 00000294c5100990 0000029481a7bed0    50072 Free
  44. 44 00000294c510cd28 00007ff8f2fe9410    50024
  45. 45 00000294c5119090 0000029481a7bed0    50072 Free
  46. 46 00000294c5125428 00007ff8f2fe9410    50024
  47. 47 00000294c5131790 0000029481a7bed0    50072 Free
  48. 48 00000294c513db28 00007ff8f2fe9410    50024
  49. 49 00000294c5149e90 0000029481a7bed0    50072 Free
  50. 50 00000294c5156228 00007ff8f2fe9410    50024
  51. 51 00000294c5162590 0000029481a7bed0    50072 Free
  52. 52 00000294c516e928 00007ff8f2fe9410    50024
  53. 53 00000294c517ac90 0000029481a7bed0    50072 Free
  54. 54 00000294c5187028 00007ff8f2fe9410    50024
  55. 55 00000294c5193390 0000029481a7bed0    50072 Free
  56. 56 00000294c519f728 00007ff8f2fe9410    50024
  57. 57 00000294c51aba90 0000029481a7bed0    50072 Free
  58. 58 00000294c51b7e28 00007ff8f2fe9410    50024
  59. 59 00000294c51c4190 0000029481a7bed0    50072 Free
  60. 60 00000294c51d0528 00007ff8f2fe9410    50024
  61. 61 00000294c51dc890 0000029481a7bed0    50072 Free
  62. 62 00000294c51e8c28 00007ff8f2fe9410    50024
  63. 63 00000294c51f4f90 0000029481a7bed0    50072 Free
  64. 64 00000294c5201328 00007ff8f2fe9410    50024
  65. 65 00000294c520d690 0000029481a7bed0    50072 Free
  66. 66 00000294c5219a28 00007ff8f2fe9410    50024
  67. 67 00000294c5225d90 0000029481a7bed0    50072 Free
  68. 68 00000294c5232128 00007ff8f2fe9410    50024
  69. 69 00000294c523e490 0000029481a7bed0    50072 Free
  70. 70 00000294c524a828 00007ff8f2fe9410    50024
  71. 71 。。。。。。(省略了)
  72. 72 00000294d7256b90 0000029481a7bed0    50072 Free
  73. 73 00000294d7262f28 00007ff8f2fe9410    50024
  74. 74 00000294d726f290 0000029481a7bed0    50072 Free
  75. 75 00000294d727b628 00007ff8f2fe9410    50024
  76. 76 00000294d7287990 0000029481a7bed0    50072 Free
  77. 77 00000294d7293d28 00007ff8f2fe9410    50024
  78. 78 00000294d72a0090 0000029481a7bed0    50072 Free
  79. 79 00000294d72ac428 00007ff8f2fe9410    50024
  80. 80 00000294d72b8790 0000029481a7bed0    50072 Free
  81. 81 00000294d72c4b28 00007ff8f2fe9410    50024
  82. 82 00000294d72d0e90 0000029481a7bed0    50072 Free
  83. 83 00000294d72dd228 00007ff8f2fe9410    50024
  84. 84 00000294d72e9590 0000029481a7bed0    50072 Free
  85. 85 00000294d72f5928 00007ff8f2fe9410    50024
  86. 86 00000294d7301c90 0000029481a7bed0    50072 Free
  87. 87 00000294d730e028 00007ff8f2fe9410    50024
  88. 88 0000029486400028 0000029481a7bed0       32 Free
  89. 89 0000029486400048 00007ff8f2fe9820   160024
  90. 90 0000029483800028 00007ff8f2e6c4d8     8184
  91. 91 0000029483802020 00007ff8f2e6c4d8     8184
  92. 92
  93. 93 Statistics:
  94. 94               MT    Count    TotalSize Class Name
  95. 95 00007ff8f3036dd0        1           24 System.IO.SyncTextReader
  96. 96 00007ff8f301f1c0        1           24 System.Threading.Tasks.Task+<>c
  97. 97 00007ff8f301a898        1           24 System.IO.Stream+NullStream
  98. 98 00007ff8f2fe0100        1           24 ExampleCore_5_9.Program
  99. 99 。。。。。。(省略了)
  100. 100 00007ff8f303c978        2          912 System.Globalization.CultureData
  101. 101 00007ff8f2fbfa88       17          976 System.String[]
  102. 102 00007ff8f2f19df8        8         3432 System.Int32[]
  103. 103 00007ff8f2e6c4d8        3        16544 System.Object[]
  104. 104 00007ff8f301f920        3        33356 System.Char[]
  105. 105 00007ff8f2f1ec08      187        39714 System.String
  106. 106 00007ff8f2fe9820        1       160024 System.Runtime.InteropServices.GCHandle[]
  107. 107 00007ff8f2fe9610        2       160048 System.Byte[][]
  108. 108 0000029481a7bed0     9846    492996800      Free
  109. 109 00007ff8f2fe9410    10004    500294202 System.Byte[]
  110. 110 Total 20148 objects
  111. 111 0:001>
复制代码
                  我们主要关注红色部分,其实我省略了很多。我们看到 Pinned 类型的句柄有 10001 个。上面的内容我注释的很清楚,就不过多的解释了。
                  
              2)、Windbg Preview 调试
                  编译项目,打开【Windbg Preview】调试器,依次点击【文件】---【Launch executable】,加载我们的项目文件:ExampleCore_5_9.exe,进入到调试器。
                  进入到调试器后,直接【g】运行调试器,我们的控制台程序输出“”字样,让我们输入分配内存的大小,我输入 50000 字节,回车。控制台继续输出“”字样,让我们输入分配内存的最大值,我输入 1000 MB(也就是 1 G MB)字节,回车。此时,我们的控制台程序输出“Press any key to GC & promo to gen1”字样。效果如图:
                  

                  此时,我们回到调试器,点击【Break】按钮进入中断模式,开始我们的调试之旅。
                  我们先看看托管堆上的统计情况,执行【!DumpHeap -stat】命令。
  1. 1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes. -stat 2 Statistics: 3           MT  Count     TotalSize Class Name 4 7fff35d3ad28      1            24 System.Collections.Generic.GenericEqualityComparer 5 7fff35d3c7d0      1            24 System.OrdinalCaseSensitiveComparer 6 7fff35d3c108      1            24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer。。。。。。(省略了)53 7fff35d62b28      4           256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider54 7fff35d38ef8      1           288 System.Collections.Generic.Dictionary+Entry[]55 7fff35dbaa30      1           312 System.Globalization.NumberFormatInfo56 7fff35d62208      1           400 System.Diagnostics.Tracing.RuntimeEventSource57 7fff35dbc978      2           912 System.Globalization.CultureData58 7fff35d3fa88     17           976 System.String[]59 7fff35c99df8      8         3,432 System.Int32[]60 7fff35bec4d8      3        16,544 System.Object[]61 7fff35d9f920      3        33,356 System.Char[]62 7fff35c9ec08    187        39,732 System.String63 [b]7fff35d69820      1       160,024 System.Runtime.InteropServices.GCHandle[](我们声明的句柄变量数组:pinnedHandles)[/b]64 [b]7fff35d69610      2       160,048 System.Byte[][](我们声明的字节数组:nonPinned 和 pinned)[/b]65 [b]01e7e9acc5b0 19,695     1,365,104 Free[/b]66 7fff35d69410 20,003 1,000,484,178 System.Byte[]67 Total 39,996 objects, 1,002,269,364 bytes
复制代码
                  由于我们在调试堆碎片的问题,所以要特别关注标注为【Free】的数据,我们看到了共有 19695 个空闲内存块,占用总大小为 1365104 字节,也就是 1.36 MB。
                  接下来,我们看看堆碎片在哪个代上,使用【!eeheap -gc】命令。
  1. 1 0:001> !DumpHeap -stat
  2. 2 Statistics:
  3. 3           MT  Count     TotalSize Class Name
  4. 4 7fff35d3ad28      1            24 System.Collections.Generic.GenericEqualityComparer<System.String>
  5. 5 7fff35d3c7d0      1            24 System.OrdinalCaseSensitiveComparer
  6. 6 7fff35d3c108      1            24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer
  7. 。。。。。。(省略了)53 7fff35d62b28      4           256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  8. 54 7fff35d38ef8      1           288 System.Collections.Generic.Dictionary<System.String, System.Object>+Entry[]
  9. 55 7fff35dbaa30      1           312 System.Globalization.NumberFormatInfo
  10. 56 7fff35d62208      1           400 System.Diagnostics.Tracing.RuntimeEventSource
  11. 57 7fff35dbc978      2           912 System.Globalization.CultureData
  12. 58 7fff35d3fa88     17           976 System.String[]
  13. 59 7fff35c99df8      8         3,432 System.Int32[]
  14. 60 7fff35bec4d8      3        16,544 System.Object[]
  15. 61 7fff35d9f920      3        33,356 System.Char[]
  16. 62 7fff35c9ec08    187        39,732 System.String
  17. 63 <strong>7fff35d69820      1       160,024 System.Runtime.InteropServices.GCHandle[](我们声明的句柄变量数组:pinnedHandles)
  18. </strong>64 <strong>7fff35d69610      2       160,048 System.Byte[][](我们声明的字节数组:nonPinned 和 pinned)
  19. </strong>65 <strong>01e7e9acc5b0 19,695     1,365,104 Free
  20. </strong>66 7fff35d69410 20,003 1,000,484,178 System.Byte[]
  21. 67 Total 39,996 objects, 1,002,269,364 bytes
复制代码
                  红色标注的指出,GC 堆的总大小刚好在 1G 左右。从输出我们注意到,有一个非常大的内存段列表。由于我们正在分配一块非常大的内存,因此,临时内存段会很快被填满,并开始创建新的第 2 代内存段。
                  我们可以使用【!DumpHeap -type Free】命令或者【!dumpheap -mt 1e7e9acc5b0】命令来找出堆上所有的空闲内存块。
  1. 1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes. -type Free 2          Address               MT           Size 3     01e7ed80c390     01e7e9acc5b0             24 Free 4     01e7ed818710     01e7e9acc5b0             24 Free 5     01e7ed824a90     01e7e9acc5b0             24 Free 6     01e7ed830e10     01e7e9acc5b0             24 Free 7     01e7ed83d190     01e7e9acc5b0             24 Free 8     01e7ed849510     01e7e9acc5b0             24 Free 9     。。。。。。(省略了)10     01e83f2f5910     01e7e9acc5b0             24 Free11     01e83f301c90     01e7e9acc5b0             24 Free12     01e83f30e010     01e7e9acc5b0             24 Free13     01e83f31a390     01e7e9acc5b0             24 Free14 15 Statistics:16           MT  Count TotalSize Class Name17 01e7e9acc5b0 19,695 1,365,104 Free18 Total 19,695 objects, 1,365,104 bytes
复制代码
                  两个命令输出差不多,
  1. 1 0:001> !DumpHeap -type Free
  2. 2          Address               MT           Size
  3. 3     01e7ed80c390     01e7e9acc5b0             24 Free
  4. 4     01e7ed818710     01e7e9acc5b0             24 Free
  5. 5     01e7ed824a90     01e7e9acc5b0             24 Free
  6. 6     01e7ed830e10     01e7e9acc5b0             24 Free
  7. 7     01e7ed83d190     01e7e9acc5b0             24 Free
  8. 8     01e7ed849510     01e7e9acc5b0             24 Free
  9. 9     。。。。。。(省略了)
  10. 10     01e83f2f5910     01e7e9acc5b0             24 Free
  11. 11     01e83f301c90     01e7e9acc5b0             24 Free
  12. 12     01e83f30e010     01e7e9acc5b0             24 Free
  13. 13     01e83f31a390     01e7e9acc5b0             24 Free
  14. 14
  15. 15 Statistics:
  16. 16           MT  Count TotalSize Class Name
  17. 17 01e7e9acc5b0 19,695 1,365,104 Free
  18. 18 Total 19,695 objects, 1,365,104 bytes
复制代码
                  我们可以拿这些 Free 块的地址和第 2 代中的起始地址比较,就知道,这些空闲对象大部分都在第 2 代中。在堆中总共的空闲块大小为 1365104 字节,也就是 1.36 MB,共 19695 个,而堆的大小为 1 GB,因此,现在堆碎片占据的比例还是比较小的,不用担心碎片问题。
                  我们【g】继续测试,恢复程序的执行,如果提示,就按任意键继续,直到控制台程序输出“Press any key to Exit”字样为止。
                  效果如图:
                  

                  此时,我们点击【Break】按钮进入中断模式,输入命令【!DumpHeap -stat】统计一下托管堆的情况。
  1. 1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes. -stat 2 Statistics: 3           MT  Count   TotalSize Class Name 4 7fff35d3ad28      1          24 System.Collections.Generic.GenericEqualityComparer 5 7fff35d3c7d0      1          24 System.OrdinalCaseSensitiveComparer 6 7fff35d3c108      1          24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer 7 7fff35d3ca50      1          24 System.OrdinalIgnoreCaseComparer 8 7fff35d60100      1          24 ExampleCore_5_9.Program 9 7fff35d9a898      1          24 System.IO.Stream+NullStream10 7fff35d9f1c0      1          24 System.Threading.Tasks.Task+c11 7fff35db6dd0      1          24 System.IO.SyncTextReader12 7fff35dbcb00      1          26 System.Globalization.CalendarId[]13 7fff35d63038      1          32 System.Diagnostics.Tracing.ActivityTracker14 7fff35d66300      1          32 System.Collections.Generic.List15 7fff35d61818      1          32 System.Guid16 7fff35d671e0      1          40 System.WeakReference[]17 7fff35d9de68      1          40 System.Threading.Tasks.TaskFactory18 7fff35d9f5e0      1          40 System.IO.TextWriter+NullTextWriter19 7fff35d6eea0      1          40 Interop+INPUT_RECORD20 7fff35d3bfc8      2          48 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalComparer21 7fff35d62338      2          48 System.Diagnostics.Tracing.TraceLoggingEventHandleTable22 7fff35d656f8      2          48 System.WeakReference23 7fff35d91428      1          48 System.Reflection.RuntimeAssembly24 7fff35d93040      1          48 System.Text.UTF8Encoding+UTF8EncodingSealed25 7fff35d93658      2          48 System.Text.EncoderReplacementFallback26 7fff35d933d0      2          48 System.Text.DecoderReplacementFallback27 7fff35db20f8      1          48 System.Text.OSEncoder28 7fff35db4278      1          48 System.IO.TextWriter+SyncTextWriter29 7fff35d9ad40      1          56 System.Text.ConsoleEncoding30 7fff35db6b50      1          56 System.Text.DecoderDBCS31 7fff35d9cfd0      1          64 System.Threading.ContextCallback32 7fff35d9edb8      1          72 System.Threading.Tasks.Task33 7fff35dbd750      1          80 System.Collections.Generic.Dictionary34 7fff35d347c8      1          80 System.Collections.Generic.Dictionary35 7fff35bea318      2          80 System.RuntimeType36 7fff35d63d00      4          96 System.WeakReference37 7fff35d94378      2          96 System.ConsolePal+WindowsConsoleStream38 7fff35db4e08      1          96 System.IO.StreamReader39 7fff35dbf910      1          96 System.Collections.Generic.Dictionary+Entry[]40 7fff35d9a3c8      1         104 System.IO.StreamWriter41 7fff35be5fa8      5         120 System.Object42 7fff35d30a90      1         128 System.OutOfMemoryException43 7fff35d30b90      1         128 System.StackOverflowException44 7fff35d30c90      1         128 System.ExecutionEngineException45 7fff35d637b8      2         128 System.Diagnostics.Tracing.EventPipeEventProvider46 7fff35d91dd8      2         128 System.Text.OSEncoding47 7fff35dbd370      1         160 System.Globalization.CalendarData48 7fff35d63a20      2         176 System.Diagnostics.Tracing.EtwEventProvider49 7fff35d685d0      1         184 System.Diagnostics.Tracing.NativeRuntimeEventSource50 7fff35d62410      2         208 System.IntPtr[]51 7fff35dbd3f0      1         208 System.Globalization.CalendarData[]52 7fff35dbb3a8      2         224 System.Globalization.CultureInfo53 7fff35d62b28      4         256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider54 7fff35d38ef8      1         288 System.Collections.Generic.Dictionary+Entry[]55 7fff35dbaa30      1         312 System.Globalization.NumberFormatInfo56 7fff35d62208      1         400 System.Diagnostics.Tracing.RuntimeEventSource57 7fff35dbc978      2         912 System.Globalization.CultureData58 7fff35d3fa88     17         976 System.String[]59 7fff35c99df8      8       3,432 System.Int32[]60 7fff35bec4d8      3      16,544 System.Object[]61 7fff35d9f920      3      33,356 System.Char[]62 7fff35c9ec08    187      39,714 System.String63 [b]7fff35d69820      1     160,024 System.Runtime.InteropServices.GCHandle[](这是我们声明的句柄数组:pinnedHandles)[/b]64 [b]7fff35d69610      2     160,048 System.Byte[][](这是我们声明的字节数组:nonPinned 和 pinned)[/b]65 [b]01e7e9acc5b0  9,846 492,996,800 Free[/b]66 7fff35d69410 10,004 500,294,202 System.Byte[]67 Total 20,148 objects, 993,711,066 bytes
复制代码
                  此时,我们再看看【Free】块,现在数量有 9846,总大小四号 492996800 字节,也就是 492 MB,我们再使用【!eeheap -gc】找到 托管堆的大小。
  1. 1 0:001> !DumpHeap -stat
  2. 2 Statistics:
  3. 3           MT  Count   TotalSize Class Name
  4. 4 7fff35d3ad28      1          24 System.Collections.Generic.GenericEqualityComparer<System.String>
  5. 5 7fff35d3c7d0      1          24 System.OrdinalCaseSensitiveComparer
  6. 6 7fff35d3c108      1          24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer
  7. 7 7fff35d3ca50      1          24 System.OrdinalIgnoreCaseComparer
  8. 8 7fff35d60100      1          24 ExampleCore_5_9.Program
  9. 9 7fff35d9a898      1          24 System.IO.Stream+NullStream
  10. 10 7fff35d9f1c0      1          24 System.Threading.Tasks.Task+<>c
  11. 11 7fff35db6dd0      1          24 System.IO.SyncTextReader
  12. 12 7fff35dbcb00      1          26 System.Globalization.CalendarId[]
  13. 13 7fff35d63038      1          32 System.Diagnostics.Tracing.ActivityTracker
  14. 14 7fff35d66300      1          32 System.Collections.Generic.List<System.WeakReference<System.Diagnostics.Tracing.EventSource>>
  15. 15 7fff35d61818      1          32 System.Guid
  16. 16 7fff35d671e0      1          40 System.WeakReference<System.Diagnostics.Tracing.EventSource>[]
  17. 17 7fff35d9de68      1          40 System.Threading.Tasks.TaskFactory
  18. 18 7fff35d9f5e0      1          40 System.IO.TextWriter+NullTextWriter
  19. 19 7fff35d6eea0      1          40 Interop+INPUT_RECORD
  20. 20 7fff35d3bfc8      2          48 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalComparer
  21. 21 7fff35d62338      2          48 System.Diagnostics.Tracing.TraceLoggingEventHandleTable
  22. 22 7fff35d656f8      2          48 System.WeakReference<System.Diagnostics.Tracing.EventSource>
  23. 23 7fff35d91428      1          48 System.Reflection.RuntimeAssembly
  24. 24 7fff35d93040      1          48 System.Text.UTF8Encoding+UTF8EncodingSealed
  25. 25 7fff35d93658      2          48 System.Text.EncoderReplacementFallback
  26. 26 7fff35d933d0      2          48 System.Text.DecoderReplacementFallback
  27. 27 7fff35db20f8      1          48 System.Text.OSEncoder
  28. 28 7fff35db4278      1          48 System.IO.TextWriter+SyncTextWriter
  29. 29 7fff35d9ad40      1          56 System.Text.ConsoleEncoding
  30. 30 7fff35db6b50      1          56 System.Text.DecoderDBCS
  31. 31 7fff35d9cfd0      1          64 System.Threading.ContextCallback
  32. 32 7fff35d9edb8      1          72 System.Threading.Tasks.Task<System.Threading.Tasks.VoidTaskResult>
  33. 33 7fff35dbd750      1          80 System.Collections.Generic.Dictionary<System.String, System.Globalization.CultureData>
  34. 34 7fff35d347c8      1          80 System.Collections.Generic.Dictionary<System.String, System.Object>
  35. 35 7fff35bea318      2          80 System.RuntimeType
  36. 36 7fff35d63d00      4          96 System.WeakReference<System.Diagnostics.Tracing.EventProvider>
  37. 37 7fff35d94378      2          96 System.ConsolePal+WindowsConsoleStream
  38. 38 7fff35db4e08      1          96 System.IO.StreamReader
  39. 39 7fff35dbf910      1          96 System.Collections.Generic.Dictionary<System.String, System.Globalization.CultureData>+Entry[]
  40. 40 7fff35d9a3c8      1         104 System.IO.StreamWriter
  41. 41 7fff35be5fa8      5         120 System.Object
  42. 42 7fff35d30a90      1         128 System.OutOfMemoryException
  43. 43 7fff35d30b90      1         128 System.StackOverflowException
  44. 44 7fff35d30c90      1         128 System.ExecutionEngineException
  45. 45 7fff35d637b8      2         128 System.Diagnostics.Tracing.EventPipeEventProvider
  46. 46 7fff35d91dd8      2         128 System.Text.OSEncoding
  47. 47 7fff35dbd370      1         160 System.Globalization.CalendarData
  48. 48 7fff35d63a20      2         176 System.Diagnostics.Tracing.EtwEventProvider
  49. 49 7fff35d685d0      1         184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  50. 50 7fff35d62410      2         208 System.IntPtr[]
  51. 51 7fff35dbd3f0      1         208 System.Globalization.CalendarData[]
  52. 52 7fff35dbb3a8      2         224 System.Globalization.CultureInfo
  53. 53 7fff35d62b28      4         256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  54. 54 7fff35d38ef8      1         288 System.Collections.Generic.Dictionary<System.String, System.Object>+Entry[]
  55. 55 7fff35dbaa30      1         312 System.Globalization.NumberFormatInfo
  56. 56 7fff35d62208      1         400 System.Diagnostics.Tracing.RuntimeEventSource
  57. 57 7fff35dbc978      2         912 System.Globalization.CultureData
  58. 58 7fff35d3fa88     17         976 System.String[]
  59. 59 7fff35c99df8      8       3,432 System.Int32[]
  60. 60 7fff35bec4d8      3      16,544 System.Object[]
  61. 61 7fff35d9f920      3      33,356 System.Char[]
  62. 62 7fff35c9ec08    187      39,714 System.String
  63. 63 <strong>7fff35d69820      1     160,024 System.Runtime.InteropServices.GCHandle[](这是我们声明的句柄数组:pinnedHandles)
  64. </strong>64 <strong>7fff35d69610      2     160,048 System.Byte[][](这是我们声明的字节数组:nonPinned 和 pinned)
  65. </strong>65 <strong>01e7e9acc5b0  9,846 492,996,800 Free
  66. </strong>66 7fff35d69410 10,004 500,294,202 System.Byte[]
  67. 67 Total 20,148 objects, 993,711,066 bytes
复制代码
                  我们看到 GC 堆总大小是 993 MB,空闲块总大小是 也就是 492 MB,可以认为堆中 50% 的碎片。可以使用【!DumpHeap】命令确认这一点。
  1.   1  1 0:001> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000294D7C00028
  4. 4 generation 1 starts at 0x00000294D7800028
  5. 5 generation 2 starts at 0x000002D518170008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 000002D49767D3F0  00000294D7C00028  00000294D7C00028  00000294D7C01000  0x0(0)  0xfd8(4056)
  10. 10 generation 1:
  11. 11 000002D49767D340  00000294D7800028  00000294D7800028  00000294D7801000  0x0(0)  0xfd8(4056)
  12. 12 generation 2:
  13. 13 0000029481B3EA70  000002D518170008  000002D518171D58  000002D518180000  0x1d50(7504)  0xfff8(65528)
  14. 14 000002D49766F270  0000029485C00028  0000029485C470F8  0000029485C68000  0x470d0(291024)  0x67fd8(425944)
  15. 15 000002D49766F320  0000029486000028  0000029486178C28  0000029486199000  0x178c00(1543168)  0x198fd8(1675224)
  16. 16 。。。。。。(省略了)
  17. 17 000002D49767CDC0  00000294D5800028  00000294D5BF6290  00000294D5C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  18. 18 000002D49767CE70  00000294D5C00028  00000294D5E01310  00000294D5E11000  0x2012e8(2101992)  0x210fd8(2166744)
  19. 19 000002D49767CF20  00000294D6000028  00000294D63F6290  00000294D6400000  0x3f6268(4153960)  0x3fffd8(4194264)
  20. 20 000002D49767CFD0  00000294D6400028  00000294D6601310  00000294D662E000  0x2012e8(2101992)  0x22dfd8(2285528)
  21. 21 000002D49767D080  00000294D6800028  00000294D6BF6290  00000294D6C00000  0x3f6268(4153960)  0x3fffd8(4194264)
  22. 22 000002D49767D130  00000294D6C00028  00000294D6E01310  00000294D6E11000  0x2012e8(2101992)  0x210fd8(2166744)
  23. 23 000002D49767D1E0  00000294D7000028  00000294D731A390  00000294D7321000  0x31a368(3253096)  0x320fd8(3280856)
  24. 24 Large object heap starts at 0x0000000000000000
  25. 25          segment             begin         allocated         committed    allocated size    committed size
  26. 26 000002D49766F3D0  0000029486400028  0000029486427160  0000029486428000  0x27138(160056)  0x27fd8(163800)
  27. 27 Pinned object heap starts at 0x0000000000000000
  28. 28 000002D49766EC40  0000029483800028  0000029483804018  0000029483811000  0x3ff0(16368)  0x10fd8(69592)
  29. 29 Total Allocated Size:              Size: 0x3b3ad610 (993711632) bytes.
  30. 30 Total Committed Size:              Size: 0x3d259da8 (1025875368) bytes.
  31. 31 ------------------------------
  32. 32 <strong>GC Allocated Heap Size:    Size: 0x3b3ad610 (993711632) bytes.
  33. </strong>33 GC Committed Heap Size:    Size: 0x3d259da8 (1025875368) bytes.  2          Address               MT           Size  3     01e7eb800028     7fff35bec4d8          8,184   4     01e7eb802020     7fff35bec4d8          8,184   5     01e7ed800028     7fff35d69410         50,024   6     [b]01e7ed80c390     01e7e9acc5b0         50,072 Free  7     01e7ed818728     7fff35d69410         50,024   8     01e7ed824a90     01e7e9acc5b0         50,072 Free  9     01e7ed830e28     7fff35d69410         50,024  10     01e7ed83d190     01e7e9acc5b0         50,072 Free 11     01e7ed849528     7fff35d69410         50,024  12     01e7ed855890     01e7e9acc5b0         50,072 Free 13     01e7ed861c28     7fff35d69410         50,024  14     01e7ed86df90     01e7e9acc5b0         50,072 Free 15     01e7ed87a328     7fff35d69410         50,024  16     01e7ed886690     01e7e9acc5b0         50,072 Free 17     01e7ed892a28     7fff35d69410         50,024  18     。。。。。。(省略了) 19     01e83edd0510     01e7e9acc5b0         50,072 Free 20     01e83eddc8a8     7fff35d69410         50,024  21     01e83ede8c10     01e7e9acc5b0         50,072 Free 22     01e83edf4fa8     7fff35d69410         50,024  23     01e83f000028     7fff35d69410         50,024  24     01e83f00c390     01e7e9acc5b0         50,072 Free 25     01e83f018728     7fff35d69410         50,024  26     01e83f024a90     01e7e9acc5b0         50,072 Free 27     01e83f030e28     7fff35d69410         50,024  28     01e83f03d190     01e7e9acc5b0         50,072 Free 29     01e83f049528     7fff35d69410         50,024  30     01e83f055890     01e7e9acc5b0         50,072 Free 31     01e83f061c28     7fff35d69410         50,024  32     01e83f06df90     01e7e9acc5b0         50,072 Free 33     01e83f07a328     7fff35d69410         50,024  34     01e83f086690     01e7e9acc5b0         50,072 Free 35     01e83f092a28     7fff35d69410         50,024  36     01e83f09ed90     01e7e9acc5b0         50,072 Free 37     01e83f0ab128     7fff35d69410         50,024  38     01e83f0b7490     01e7e9acc5b0         50,072 Free 39     01e83f0c3828     7fff35d69410         50,024  40     01e83f0cfb90     01e7e9acc5b0         50,072 Free 41     01e83f0dbf28     7fff35d69410         50,024  42     01e83f0e8290     01e7e9acc5b0         50,072 Free 43     01e83f0f4628     7fff35d69410         50,024  44     01e83f100990     01e7e9acc5b0         50,072 Free 45     01e83f10cd28     7fff35d69410         50,024  46     01e83f119090     01e7e9acc5b0         50,072 Free 47     01e83f125428     7fff35d69410         50,024  48     01e83f131790     01e7e9acc5b0         50,072 Free 49     01e83f13db28     7fff35d69410         50,024  50     01e83f149e90     01e7e9acc5b0         50,072 Free 51     01e83f156228     7fff35d69410         50,024  52     01e83f162590     01e7e9acc5b0         50,072 Free 53     01e83f16e928     7fff35d69410         50,024  54     01e83f17ac90     01e7e9acc5b0         50,072 Free 55     01e83f187028     7fff35d69410         50,024  56     01e83f193390     01e7e9acc5b0         50,072 Free 57     01e83f19f728     7fff35d69410         50,024  58     01e83f1aba90     01e7e9acc5b0         50,072 Free 59     01e83f1b7e28     7fff35d69410         50,024  60     01e83f1c4190     01e7e9acc5b0         50,072 Free 61     01e83f1d0528     7fff35d69410         50,024  62     01e83f1dc890     01e7e9acc5b0         50,072 Free 63     01e83f1e8c28     7fff35d69410         50,024  64     01e83f1f4f90     01e7e9acc5b0         50,072 Free 65     01e83f201328     7fff35d69410         50,024  66     01e83f20d690     01e7e9acc5b0         50,072 Free 67     01e83f219a28     7fff35d69410         50,024  68     01e83f225d90     01e7e9acc5b0         50,072 Free 69     01e83f232128     7fff35d69410         50,024  70     01e83f23e490     01e7e9acc5b0         50,072 Free 71     01e83f24a828     7fff35d69410         50,024  72     01e83f256b90     01e7e9acc5b0         50,072 Free 73     01e83f262f28     7fff35d69410         50,024  74     01e83f26f290     01e7e9acc5b0         50,072 Free 75     01e83f27b628     7fff35d69410         50,024  76     01e83f287990     01e7e9acc5b0         50,072 Free 77     01e83f293d28     7fff35d69410         50,024  78     01e83f2a0090     01e7e9acc5b0         50,072 Free 79     01e83f2ac428     7fff35d69410         50,024  80     01e83f2b8790     01e7e9acc5b0         50,072 Free 81     01e83f2c4b28     7fff35d69410         50,024  82     01e83f2d0e90     01e7e9acc5b0         50,072 Free 83     01e83f2dd228     7fff35d69410         50,024  84     01e83f2e9590     01e7e9acc5b0         50,072 Free 85     01e83f2f5928     7fff35d69410         50,024  86     01e83f301c90     01e7e9acc5b0         50,072 Free[/b] 87     01e83f30e028     7fff35d69410         50,024  88     02287ffa0008     7fff35c9ec08             24  89     02287ffa0020     7fff35bea318             40 。。。。。。(省略了)237     02287ffa1c50     7fff35c9ec08             24 238     02287ffa1c68     7fff35c9ec08             24 239     02287ffa1c80     7fff35c9ec08             24 240     02287ffa1c98     7fff35c9ec08             62 241     02287ffa1cd8     7fff35c9ec08             50 242     02287ffa1d10     7fff35d6eea0             40 243     02287ffa1d38     7fff35c9ec08             28 244 245 Statistics:246           MT  Count   TotalSize Class Name247 7fff35d3ad28      1          24 System.Collections.Generic.GenericEqualityComparer248 7fff35d3c7d0      1          24 System.OrdinalCaseSensitiveComparer249 7fff35d3c108      1          24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer250 7fff35d3ca50      1          24 System.OrdinalIgnoreCaseComparer251 7fff35d60100      1          24 ExampleCore_5_9.Program252 7fff35d9a898      1          24 System.IO.Stream+NullStream253 7fff35d9f1c0      1          24 System.Threading.Tasks.Task+c254 7fff35db6dd0      1          24 System.IO.SyncTextReader255 7fff35dbcb00      1          26 System.Globalization.CalendarId[]256 7fff35d63038      1          32 System.Diagnostics.Tracing.ActivityTracker257 7fff35d66300      1          32 System.Collections.Generic.List258 7fff35d61818      1          32 System.Guid259 7fff35d671e0      1          40 System.WeakReference[]260 7fff35d9de68      1          40 System.Threading.Tasks.TaskFactory261 7fff35d9f5e0      1          40 System.IO.TextWriter+NullTextWriter262 7fff35d6eea0      1          40 Interop+INPUT_RECORD263 7fff35d3bfc8      2          48 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalComparer264 7fff35d62338      2          48 System.Diagnostics.Tracing.TraceLoggingEventHandleTable265 7fff35d656f8      2          48 System.WeakReference266 7fff35d91428      1          48 System.Reflection.RuntimeAssembly267 7fff35d93040      1          48 System.Text.UTF8Encoding+UTF8EncodingSealed268 7fff35d93658      2          48 System.Text.EncoderReplacementFallback269 7fff35d933d0      2          48 System.Text.DecoderReplacementFallback270 7fff35db20f8      1          48 System.Text.OSEncoder271 7fff35db4278      1          48 System.IO.TextWriter+SyncTextWriter272 7fff35d9ad40      1          56 System.Text.ConsoleEncoding273 7fff35db6b50      1          56 System.Text.DecoderDBCS274 7fff35d9cfd0      1          64 System.Threading.ContextCallback275 7fff35d9edb8      1          72 System.Threading.Tasks.Task276 7fff35dbd750      1          80 System.Collections.Generic.Dictionary277 7fff35d347c8      1          80 System.Collections.Generic.Dictionary278 7fff35bea318      2          80 System.RuntimeType279 7fff35d63d00      4          96 System.WeakReference280 7fff35d94378      2          96 System.ConsolePal+WindowsConsoleStream281 7fff35db4e08      1          96 System.IO.StreamReader282 7fff35dbf910      1          96 System.Collections.Generic.Dictionary+Entry[]283 7fff35d9a3c8      1         104 System.IO.StreamWriter284 7fff35be5fa8      5         120 System.Object285 7fff35d30a90      1         128 System.OutOfMemoryException286 7fff35d30b90      1         128 System.StackOverflowException287 7fff35d30c90      1         128 System.ExecutionEngineException288 7fff35d637b8      2         128 System.Diagnostics.Tracing.EventPipeEventProvider289 7fff35d91dd8      2         128 System.Text.OSEncoding290 7fff35dbd370      1         160 System.Globalization.CalendarData291 7fff35d63a20      2         176 System.Diagnostics.Tracing.EtwEventProvider292 7fff35d685d0      1         184 System.Diagnostics.Tracing.NativeRuntimeEventSource293 7fff35d62410      2         208 System.IntPtr[]294 7fff35dbd3f0      1         208 System.Globalization.CalendarData[]295 7fff35dbb3a8      2         224 System.Globalization.CultureInfo296 7fff35d62b28      4         256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider297 7fff35d38ef8      1         288 System.Collections.Generic.Dictionary+Entry[]298 7fff35dbaa30      1         312 System.Globalization.NumberFormatInfo299 7fff35d62208      1         400 System.Diagnostics.Tracing.RuntimeEventSource300 7fff35dbc978      2         912 System.Globalization.CultureData301 7fff35d3fa88     17         976 System.String[]302 7fff35c99df8      8       3,432 System.Int32[]303 7fff35bec4d8      3      16,544 System.Object[]304 7fff35d9f920      3      33,356 System.Char[]305 7fff35c9ec08    187      39,714 System.String306 7fff35d69820      1     160,024 System.Runtime.InteropServices.GCHandle[]307 7fff35d69610      2     160,048 System.Byte[][]308 01e7e9acc5b0  9,846 492,996,800 Free309 7fff35d69410 10,004 500,294,202 System.Byte[]310 Total 20,148 objects, 993,711,066 bytes
复制代码
                  红色标注的可以很清楚的看到,分配一个对象,空闲一个对象,交替出现。我们知道GC执行垃圾收集的时候会紧缩和合并,但是这里并没有执行紧缩和合并的操作,原因之一就是在堆上存在一些被固定住(不能移动的)的对象。
                  为了确定是否是有些对象被固定了,我们可以使用【!GCHandles】命令来看看进程中是否包含了“Pinned”类型的句柄。
  1.   1 0:001> !DumpHeap
  2.   2          Address               MT           Size
  3.   3     01e7eb800028     7fff35bec4d8          8,184
  4.   4     01e7eb802020     7fff35bec4d8          8,184
  5.   5     01e7ed800028     7fff35d69410         50,024
  6.   6     <strong>01e7ed80c390     01e7e9acc5b0         50,072 Free
  7.   7     01e7ed818728     7fff35d69410         50,024
  8.   8     01e7ed824a90     01e7e9acc5b0         50,072 Free
  9.   9     01e7ed830e28     7fff35d69410         50,024
  10. 10     01e7ed83d190     01e7e9acc5b0         50,072 Free
  11. 11     01e7ed849528     7fff35d69410         50,024
  12. 12     01e7ed855890     01e7e9acc5b0         50,072 Free
  13. 13     01e7ed861c28     7fff35d69410         50,024
  14. 14     01e7ed86df90     01e7e9acc5b0         50,072 Free
  15. 15     01e7ed87a328     7fff35d69410         50,024
  16. 16     01e7ed886690     01e7e9acc5b0         50,072 Free
  17. 17     01e7ed892a28     7fff35d69410         50,024
  18. 18     。。。。。。(省略了)
  19. 19     01e83edd0510     01e7e9acc5b0         50,072 Free
  20. 20     01e83eddc8a8     7fff35d69410         50,024
  21. 21     01e83ede8c10     01e7e9acc5b0         50,072 Free
  22. 22     01e83edf4fa8     7fff35d69410         50,024
  23. 23     01e83f000028     7fff35d69410         50,024
  24. 24     01e83f00c390     01e7e9acc5b0         50,072 Free
  25. 25     01e83f018728     7fff35d69410         50,024
  26. 26     01e83f024a90     01e7e9acc5b0         50,072 Free
  27. 27     01e83f030e28     7fff35d69410         50,024
  28. 28     01e83f03d190     01e7e9acc5b0         50,072 Free
  29. 29     01e83f049528     7fff35d69410         50,024
  30. 30     01e83f055890     01e7e9acc5b0         50,072 Free
  31. 31     01e83f061c28     7fff35d69410         50,024
  32. 32     01e83f06df90     01e7e9acc5b0         50,072 Free
  33. 33     01e83f07a328     7fff35d69410         50,024
  34. 34     01e83f086690     01e7e9acc5b0         50,072 Free
  35. 35     01e83f092a28     7fff35d69410         50,024
  36. 36     01e83f09ed90     01e7e9acc5b0         50,072 Free
  37. 37     01e83f0ab128     7fff35d69410         50,024
  38. 38     01e83f0b7490     01e7e9acc5b0         50,072 Free
  39. 39     01e83f0c3828     7fff35d69410         50,024
  40. 40     01e83f0cfb90     01e7e9acc5b0         50,072 Free
  41. 41     01e83f0dbf28     7fff35d69410         50,024
  42. 42     01e83f0e8290     01e7e9acc5b0         50,072 Free
  43. 43     01e83f0f4628     7fff35d69410         50,024
  44. 44     01e83f100990     01e7e9acc5b0         50,072 Free
  45. 45     01e83f10cd28     7fff35d69410         50,024
  46. 46     01e83f119090     01e7e9acc5b0         50,072 Free
  47. 47     01e83f125428     7fff35d69410         50,024
  48. 48     01e83f131790     01e7e9acc5b0         50,072 Free
  49. 49     01e83f13db28     7fff35d69410         50,024
  50. 50     01e83f149e90     01e7e9acc5b0         50,072 Free
  51. 51     01e83f156228     7fff35d69410         50,024
  52. 52     01e83f162590     01e7e9acc5b0         50,072 Free
  53. 53     01e83f16e928     7fff35d69410         50,024
  54. 54     01e83f17ac90     01e7e9acc5b0         50,072 Free
  55. 55     01e83f187028     7fff35d69410         50,024
  56. 56     01e83f193390     01e7e9acc5b0         50,072 Free
  57. 57     01e83f19f728     7fff35d69410         50,024
  58. 58     01e83f1aba90     01e7e9acc5b0         50,072 Free
  59. 59     01e83f1b7e28     7fff35d69410         50,024
  60. 60     01e83f1c4190     01e7e9acc5b0         50,072 Free
  61. 61     01e83f1d0528     7fff35d69410         50,024
  62. 62     01e83f1dc890     01e7e9acc5b0         50,072 Free
  63. 63     01e83f1e8c28     7fff35d69410         50,024
  64. 64     01e83f1f4f90     01e7e9acc5b0         50,072 Free
  65. 65     01e83f201328     7fff35d69410         50,024
  66. 66     01e83f20d690     01e7e9acc5b0         50,072 Free
  67. 67     01e83f219a28     7fff35d69410         50,024
  68. 68     01e83f225d90     01e7e9acc5b0         50,072 Free
  69. 69     01e83f232128     7fff35d69410         50,024
  70. 70     01e83f23e490     01e7e9acc5b0         50,072 Free
  71. 71     01e83f24a828     7fff35d69410         50,024
  72. 72     01e83f256b90     01e7e9acc5b0         50,072 Free
  73. 73     01e83f262f28     7fff35d69410         50,024
  74. 74     01e83f26f290     01e7e9acc5b0         50,072 Free
  75. 75     01e83f27b628     7fff35d69410         50,024
  76. 76     01e83f287990     01e7e9acc5b0         50,072 Free
  77. 77     01e83f293d28     7fff35d69410         50,024
  78. 78     01e83f2a0090     01e7e9acc5b0         50,072 Free
  79. 79     01e83f2ac428     7fff35d69410         50,024
  80. 80     01e83f2b8790     01e7e9acc5b0         50,072 Free
  81. 81     01e83f2c4b28     7fff35d69410         50,024
  82. 82     01e83f2d0e90     01e7e9acc5b0         50,072 Free
  83. 83     01e83f2dd228     7fff35d69410         50,024
  84. 84     01e83f2e9590     01e7e9acc5b0         50,072 Free
  85. 85     01e83f2f5928     7fff35d69410         50,024
  86. 86     01e83f301c90     01e7e9acc5b0         50,072 Free
  87. </strong> 87     01e83f30e028     7fff35d69410         50,024
  88. 88     02287ffa0008     7fff35c9ec08             24
  89. 89     02287ffa0020     7fff35bea318             40
  90. 。。。。。。(省略了)
  91. 237     02287ffa1c50     7fff35c9ec08             24
  92. 238     02287ffa1c68     7fff35c9ec08             24
  93. 239     02287ffa1c80     7fff35c9ec08             24
  94. 240     02287ffa1c98     7fff35c9ec08             62
  95. 241     02287ffa1cd8     7fff35c9ec08             50
  96. 242     02287ffa1d10     7fff35d6eea0             40
  97. 243     02287ffa1d38     7fff35c9ec08             28
  98. 244
  99. 245 Statistics:
  100. 246           MT  Count   TotalSize Class Name
  101. 247 7fff35d3ad28      1          24 System.Collections.Generic.GenericEqualityComparer<System.String>
  102. 248 7fff35d3c7d0      1          24 System.OrdinalCaseSensitiveComparer
  103. 249 7fff35d3c108      1          24 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer
  104. 250 7fff35d3ca50      1          24 System.OrdinalIgnoreCaseComparer
  105. 251 7fff35d60100      1          24 ExampleCore_5_9.Program
  106. 252 7fff35d9a898      1          24 System.IO.Stream+NullStream
  107. 253 7fff35d9f1c0      1          24 System.Threading.Tasks.Task+<>c
  108. 254 7fff35db6dd0      1          24 System.IO.SyncTextReader
  109. 255 7fff35dbcb00      1          26 System.Globalization.CalendarId[]
  110. 256 7fff35d63038      1          32 System.Diagnostics.Tracing.ActivityTracker
  111. 257 7fff35d66300      1          32 System.Collections.Generic.List<System.WeakReference<System.Diagnostics.Tracing.EventSource>>
  112. 258 7fff35d61818      1          32 System.Guid
  113. 259 7fff35d671e0      1          40 System.WeakReference<System.Diagnostics.Tracing.EventSource>[]
  114. 260 7fff35d9de68      1          40 System.Threading.Tasks.TaskFactory
  115. 261 7fff35d9f5e0      1          40 System.IO.TextWriter+NullTextWriter
  116. 262 7fff35d6eea0      1          40 Interop+INPUT_RECORD
  117. 263 7fff35d3bfc8      2          48 System.Collections.Generic.NonRandomizedStringEqualityComparer+OrdinalComparer
  118. 264 7fff35d62338      2          48 System.Diagnostics.Tracing.TraceLoggingEventHandleTable
  119. 265 7fff35d656f8      2          48 System.WeakReference<System.Diagnostics.Tracing.EventSource>
  120. 266 7fff35d91428      1          48 System.Reflection.RuntimeAssembly
  121. 267 7fff35d93040      1          48 System.Text.UTF8Encoding+UTF8EncodingSealed
  122. 268 7fff35d93658      2          48 System.Text.EncoderReplacementFallback
  123. 269 7fff35d933d0      2          48 System.Text.DecoderReplacementFallback
  124. 270 7fff35db20f8      1          48 System.Text.OSEncoder
  125. 271 7fff35db4278      1          48 System.IO.TextWriter+SyncTextWriter
  126. 272 7fff35d9ad40      1          56 System.Text.ConsoleEncoding
  127. 273 7fff35db6b50      1          56 System.Text.DecoderDBCS
  128. 274 7fff35d9cfd0      1          64 System.Threading.ContextCallback
  129. 275 7fff35d9edb8      1          72 System.Threading.Tasks.Task<System.Threading.Tasks.VoidTaskResult>
  130. 276 7fff35dbd750      1          80 System.Collections.Generic.Dictionary<System.String, System.Globalization.CultureData>
  131. 277 7fff35d347c8      1          80 System.Collections.Generic.Dictionary<System.String, System.Object>
  132. 278 7fff35bea318      2          80 System.RuntimeType
  133. 279 7fff35d63d00      4          96 System.WeakReference<System.Diagnostics.Tracing.EventProvider>
  134. 280 7fff35d94378      2          96 System.ConsolePal+WindowsConsoleStream
  135. 281 7fff35db4e08      1          96 System.IO.StreamReader
  136. 282 7fff35dbf910      1          96 System.Collections.Generic.Dictionary<System.String, System.Globalization.CultureData>+Entry[]
  137. 283 7fff35d9a3c8      1         104 System.IO.StreamWriter
  138. 284 7fff35be5fa8      5         120 System.Object
  139. 285 7fff35d30a90      1         128 System.OutOfMemoryException
  140. 286 7fff35d30b90      1         128 System.StackOverflowException
  141. 287 7fff35d30c90      1         128 System.ExecutionEngineException
  142. 288 7fff35d637b8      2         128 System.Diagnostics.Tracing.EventPipeEventProvider
  143. 289 7fff35d91dd8      2         128 System.Text.OSEncoding
  144. 290 7fff35dbd370      1         160 System.Globalization.CalendarData
  145. 291 7fff35d63a20      2         176 System.Diagnostics.Tracing.EtwEventProvider
  146. 292 7fff35d685d0      1         184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  147. 293 7fff35d62410      2         208 System.IntPtr[]
  148. 294 7fff35dbd3f0      1         208 System.Globalization.CalendarData[]
  149. 295 7fff35dbb3a8      2         224 System.Globalization.CultureInfo
  150. 296 7fff35d62b28      4         256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  151. 297 7fff35d38ef8      1         288 System.Collections.Generic.Dictionary<System.String, System.Object>+Entry[]
  152. 298 7fff35dbaa30      1         312 System.Globalization.NumberFormatInfo
  153. 299 7fff35d62208      1         400 System.Diagnostics.Tracing.RuntimeEventSource
  154. 300 7fff35dbc978      2         912 System.Globalization.CultureData
  155. 301 7fff35d3fa88     17         976 System.String[]
  156. 302 7fff35c99df8      8       3,432 System.Int32[]
  157. 303 7fff35bec4d8      3      16,544 System.Object[]
  158. 304 7fff35d9f920      3      33,356 System.Char[]
  159. 305 7fff35c9ec08    187      39,714 System.String
  160. 306 7fff35d69820      1     160,024 System.Runtime.InteropServices.GCHandle[]
  161. 307 7fff35d69610      2     160,048 System.Byte[][]
  162. 308 01e7e9acc5b0  9,846 492,996,800 Free
  163. 309 7fff35d69410 10,004 500,294,202 System.Byte[]
  164. 310 Total 20,148 objects, 993,711,066 bytes
复制代码
                  进程中有 10001 个类型为“Pinned”的句柄,有 10000 个这样的句柄用于固定字节数组。

            B2、调试源码:ExampleCore_5_10
               调试任务:如何调试 .NET 程序的内存泄漏            
              1)、NTSD 调试
                  编译项目,首先,把我们的控制台程序运行起来,然后再打开【Visual Studio 2022 Developer Command Prompt v17.9.6】命令行工具,输入命令【NTSD -pn ExampleCore_5_10.exe】打开调试器。效果如图:
                  

                  此时,调试器中断执行,如图:
                  

                  在看看我们的控制台程序,执行情况如图:
                  

                  准备就绪,开始我们的调试,先看看 GC 堆的情况,执行【!eeheap -gc】命令。
  1. 1 0:001> !GCHandles
  2. 2           Handle Type                  Object     Size             Data Type
  3. 3 000001E7E99D11B8 WeakShort   000001e7edc08f50      400                  System.Diagnostics.Tracing.RuntimeEventSource
  4. 4 000001E7E99D11C0 WeakShort   000001e7edc09310      184                  System.Diagnostics.Tracing.NativeRuntimeEventSource
  5. 5 000001E7E99D11C8 WeakShort   000001e7edc094f8       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  6. 6 000001E7E99D11D0 WeakShort   000001e7edc09448       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  7. 7 000001E7E99D11D8 WeakShort   000001e7edc09230       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  8. 8 000001E7E99D11E0 WeakShort   000001e7edc09180       64                  System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  9. 9 000001E7E99D1390 Strong      000001e7edc134c8      176                  System.Object[]
  10. 10 000001E7E99D1398 Strong      000001e7eb802020     8184                  System.Object[]
  11. 11 000001E7E99D13A0 Strong      000001e7edc09270       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  12. 12 000001E7E99D13A8 Strong      000001e7edc09538       64                  System.Diagnostics.Tracing.EventPipeEventProvider
  13. 13 000001E7E99D13B0 Strong      000001e7edc09488       88                  System.Diagnostics.Tracing.EtwEventProvider
  14. 14 000001E7E99D13B8 Strong      000001e7edc091c0       88                  System.Diagnostics.Tracing.EtwEventProvider
  15. 15 000001E7E99D13C8 Strong      000001e7edc00188      128                  System.ExecutionEngineException
  16. 16 000001E7E99D13D0 Strong      000001e7edc00108      128                  System.StackOverflowException
  17. 17 000001E7E99D13D8 Strong      000001e7edc00088      128                  System.OutOfMemoryException
  18. 18 000001E7E99D13E0 Strong      000001e7edc00028       96                  System.Int32[]
  19. 19 000001E7E99D13E8 Strong      000001e7eb800028     8184                  System.Object[]
  20. <strong>20 000001E7E99D1400 Pinned      000001e7f08b74a8    50024                  System.Byte[]
  21. 21 000001E7E99D1408 Pinned      000001e7f089eda8    50024                  System.Byte[]
  22. 22 。。。。。。(省略了)
  23. 23 000001E7E99D1490 Pinned      000001e7f06f5928    50024                  System.Byte[]
  24. 24 000001E7E99D1498 Pinned      000001e7f06dd228    50024                  System.Byte[]
  25. 25 000001E7E99D14A0 Pinned      000001e7f06c4b28    50024                  System.Byte[]
  26. 26 000001E7E99D14A8 Pinned      000001e7f06ac428    50024                  System.Byte[]
  27. 27 000001E7E99D14B0 Pinned      000001e7f0693d28    50024                  System.Byte[]
  28. 28 000001E7E99D14B8 Pinned      000001e7f067b628    50024                  System.Byte[]
  29. 29 000001E7E99D14C0 Pinned      000001e7f0662f28    50024                  System.Byte[]
  30. 30 000001E7E99D14C8 Pinned      000001e7f064a828    50024                  System.Byte[]
  31. 31 000001E7E99D14D0 Pinned      000001e7f0632128    50024                  System.Byte[]
  32. 32 000001E7E99D14D8 Pinned      000001e7f0619a28    50024                  System.Byte[]
  33. 33 000001E7E99D14E0 Pinned      000001e7f0601328    50024                  System.Byte[]
  34. 34 。。。。。。(省略了)
  35. 35 000001E7E99D4F70 Pinned      000001e7feb0e028    50024                  System.Byte[]
  36. 36 000001E7E99D4F78 Pinned      000001e7feaf5928    50024                  System.Byte[]
  37. 37 000001E7E99D4F80 Pinned      000001e7feadd228    50024                  System.Byte[]
  38. 38 000001E7E99D4F88 Pinned      000001e7feac4b28    50024                  System.Byte[]
  39. 39 000001E7E99D4F90 Pinned      000001e7feaac428    50024                  System.Byte[]
  40. 40 000001E7E99D4F98 Pinned      000001e7fea93d28    50024                  System.Byte[]
  41. 41 000001E7E99D4FA0 Pinned      000001e7fea7b628    50024                  System.Byte[]
  42. 42 000001E7E99D4FA8 Pinned      000001e7fea62f28    50024                  System.Byte[]
  43. 43 。。。。。。(省略了)
  44. 44 000001E7E99D8EC0 Pinned      000001e80f232128    50024                  System.Byte[]
  45. 45 000001E7E99D8EC8 Pinned      000001e80f219a28    50024                  System.Byte[]
  46. 46 000001E7E99D8ED0 Pinned      000001e80f201328    50024                  System.Byte[]
  47. 47 000001E7E99D8ED8 Pinned      000001e80f1e8c28    50024                  System.Byte[]
  48. 48 000001E7E99D8EE0 Pinned      000001e80f1d0528    50024                  System.Byte[]
  49. 49 000001E7E99D8EE8 Pinned      000001e80f1b7e28    50024                  System.Byte[]
  50. 50 000001E7E99D8EF0 Pinned      000001e80f19f728    50024                  System.Byte[]
  51. 51 000001E7E99D8EF8 Pinned      000001e80f187028    50024                  System.Byte[]
  52. 52 。。。。。。(省略了)
  53. 53 000001E7EB445DB8 Pinned      000001e83f24a828    50024                  System.Byte[]
  54. 54 000001E7EB445DC0 Pinned      000001e83f232128    50024                  System.Byte[]
  55. 55 000001E7EB445DC8 Pinned      000001e83f219a28    50024                  System.Byte[]
  56. 56 000001E7EB445DD0 Pinned      000001e83f201328    50024                  System.Byte[]
  57. 57 000001E7EB445DD8 Pinned      000001e83f1e8c28    50024                  System.Byte[]
  58. 58 000001E7EB445DE0 Pinned      000001e83f1d0528    50024                  System.Byte[]
  59. 59 000001E7EB445DE8 Pinned      000001e83f1b7e28    50024                  System.Byte[]
  60. 60 000001E7EB445DF0 Pinned      000001e83f19f728    50024                  System.Byte[]
  61. 61 000001E7EB445DF8 Pinned      000001e83f187028    50024                  System.Byte[]
  62. </strong>62
  63. 63 Statistics:
  64. 64               MT    Count    TotalSize Class Name
  65. 65 00007fff35be5fa8        1           24 System.Object
  66. 66 00007fff35c99df8        1           96 System.Int32[]
  67. 67 00007fff35d637b8        2          128 System.Diagnostics.Tracing.EventPipeEventProvider
  68. 68 00007fff35d30c90        1          128 System.ExecutionEngineException
  69. 69 00007fff35d30b90        1          128 System.StackOverflowException
  70. 70 00007fff35d30a90        1          128 System.OutOfMemoryException
  71. 71 00007fff35d63a20        2          176 System.Diagnostics.Tracing.EtwEventProvider
  72. 72 00007fff35d685d0        1          184 System.Diagnostics.Tracing.NativeRuntimeEventSource
  73. 73 00007fff35d62b28        4          256 System.Diagnostics.Tracing.EventSource+OverrideEventProvider
  74. 74 00007fff35d62208        1          400 System.Diagnostics.Tracing.RuntimeEventSource
  75. 75 00007fff35bec4d8        3        16544 System.Object[]
  76. 76 <strong>00007fff35d69410    10000    500240000 System.Byte[](有 10000 个用于固定字节数组)
  77. </strong>77 Total 10018 objects
  78. 78
  79. 79 Handles:
  80. 80     Strong Handles:       11
  81. 81     <strong>Pinned Handles:      </strong> <strong>10001(Pinned 句柄有这么多)</strong>
  82. 82     Weak Short Handles:   6
复制代码
                  我看完了,感觉没啥异常情况,在看看我们的引用程序域有没有什么问题,执行命令【!DumpDomain】。
  1. 1 0:007> !eeheap -gc
  2. 2 Number of GC Heaps: 1
  3. 3 generation 0 starts at 0x00000206CB400028
  4. 4 generation 1 starts at 0x00000206CB000028
  5. 5 generation 2 starts at 0x000002475D5C0008
  6. 6 ephemeral segment allocation context: none
  7. 7          segment             begin         allocated         committed    allocated size    committed size
  8. 8 generation 0:
  9. 9 00000246DCABF320  00000206CB400028  00000206CB40E070  00000206CB761000  0xe048(57416)  0x360fd8(3543000)
  10. 10 generation 1:
  11. 11 00000246DCABF270  00000206CB000028  00000206CB015378  00000206CB051000  0x15350(86864)  0x50fd8(331736)
  12. 12 generation 2:
  13. 13 00000206C6E61A60  000002475D5C0008  000002475D627D48  000002475D630000  0x67d40(425280)  0x6fff8(458744)
  14. 14 00000246DCABF1C0  00000206CAC00028  00000206CAC588D0  00000206CAC61000  0x588a8(362664)  0x60fd8(397272)
  15. 15 Large object heap starts at 0x0000000000000000
  16. 16          segment             begin         allocated         committed    allocated size    committed size
  17. 17 00000246DCABF3D0  00000206CB800028  00000206CB800028  00000206CB801000  0x0(0)  0xfd8(4056)
  18. 18 Pinned object heap starts at 0x0000000000000000
  19. 19 00000246DCABEC40  00000206C8C00028  00000206C8C13F60  00000206C8C21000  0x13f38(81720)  0x20fd8(135128)
  20. 20 Total Allocated Size:              Size: 0xf78b8 (1013944) bytes.
  21. 21 Total Committed Size:              Size: 0x483f58 (4734808) bytes.
  22. 22 ------------------------------
  23. 23 GC Allocated Heap Size:    Size: 0xf78b8 (1013944) bytes.
  24. 24 GC Committed Heap Size:    Size: 0x483f58 (4734808) bytes.
复制代码
                  在【Domain 1】应用程序域中,加载了很多动态的程序集,太多了,不用过脑子,都知道有问题。
                  接下来,我我们看看这个模块有什么特别之处,执行命令【!DumpModule 00007ff913982df0】,我们就随机的选择最后一个程序集。
  1. 1 0:007> !DumpDomain
  2. 2 。。。。。。(无关紧要的省略了)
  3. 3 Assembly:           000002475f74abd0 (Dynamic) []
  4. 4 ClassLoader:        000002475D9EF470
  5. 5   Module
  6. 6   00007ff911a52b20    Dynamic Module
  7. 7
  8. 8 Assembly:           000002475f74a4b0 (Dynamic) []
  9. 9 ClassLoader:        000002475D9EFC00
  10. 10   Module
  11. 11   00007ff911a535e8    Dynamic Module
  12. 12
  13. 13 Assembly:           000002475f74b470 (Dynamic) []
  14. 14 ClassLoader:        000002475D9EF7E0
  15. 15   Module
  16. 16   00007ff911a540b0    Dynamic Module
  17. 17
  18. 18 Assembly:           000002475f74a870 (Dynamic) []
  19. 19 ClassLoader:        000002475D9EF5D0
  20. 20   Module
  21. 21   00007ff911a54b78    Dynamic Module
  22. 22
  23. 23 Assembly:           000002475f74c010 (Dynamic) []
  24. 24 ClassLoader:        000002475D9EEEF0
  25. 25   Module
  26. 26   00007ff911a55640    Dynamic Module
  27. 27
  28. 28 。。。。。。(太多了,省略了)
  29. 29
  30. 30 Assembly:           0000024760ec5970 (Dynamic) []
  31. 31 ClassLoader:        0000024760F1F850
  32. 32   Module
  33. 33   00007ff9124ddd38    Dynamic Module
  34. 34
  35. 35 Assembly:           0000024760ec6330 (Dynamic) []
  36. 36 ClassLoader:        0000024760F1F430
  37. 37   Module
  38. 38   00007ff9124de800    Dynamic Module
  39. 39
  40. 40 Assembly:           0000024760ec5c70 (Dynamic) []
  41. 41 ClassLoader:        0000024760F1E670
  42. 42   Module
  43. 43   00007ff9124df2c8    Dynamic Module
  44. 44
  45. 45 Assembly:           0000024760ec5df0 (Dynamic) []
  46. 46 ClassLoader:        0000024760F1F9B0
  47. 47   Module
  48. 48   00007ff912530000    Dynamic Module
  49. 49
  50. 50 Assembly:           0000024760ec6090 (Dynamic) []
  51. 51 ClassLoader:        0000024760F1DE30
  52. 52   Module
  53. 53   00007ff912530ac8    Dynamic Module
  54. 54
  55. 55 Assembly:           0000024760ec8490 (Dynamic) []
  56. 56 ClassLoader:        0000024760F1DB70
  57. 57   Module
  58. 58   00007ff912531590    Dynamic Module
  59. 59
  60. 60 。。。。。。(太多了,省略了)
  61. 61
  62. 62 Assembly:           000002476352caa0 (Dynamic) []
  63. 63 ClassLoader:        0000024762C391C0
  64. 64   Module
  65. 65   00007ff91379d270    Dynamic Module
  66. 66
  67. 67 Assembly:           000002476352c9e0 (Dynamic) []
  68. 68 ClassLoader:        0000024762C39530
  69. 69   Module
  70. 70   00007ff91379dd38    Dynamic Module
  71. 71
  72. 72 Assembly:           000002476352db80 (Dynamic) []
  73. 73 ClassLoader:        0000024762C39C10
  74. 74   Module
  75. 75   00007ff91379e800    Dynamic Module
  76. 76
  77. 77 Assembly:           000002476352f680 (Dynamic) []
  78. 78 ClassLoader:        0000024762C39950
  79. 79   Module
  80. 80   00007ff91379f2c8    Dynamic Module
  81. 81
  82. 82 Assembly:           000002476352efc0 (Dynamic) []
  83. 83 ClassLoader:        0000024762C39CC0
  84. 84   Module
  85. 85   00007ff913800000    Dynamic Module
  86. 86
  87. 87 。。。。。。(省略了)
  88. 88
  89. 89 Assembly:           0000024763a92070 (Dynamic) []
  90. 90 ClassLoader:        0000024763A30020
  91. 91   Module
  92. 92   <strong>00007ff913982df0    Dynamic Module</strong>
  93. 93
  94. 94 0:007>
复制代码
                  特性一行是我们特别要关注的,Reflection 表示是反射的,IsDynamic 表示是动态创建的(不是程序员搞的),IsInMemory 直接在内存中的,3个特性就是告诉我们,这个模块是通过反射技术、由系统创在内存中直接创建的。
                  它既然有执行调用,肯定有调用栈,调用栈肯定是有我们的程序触发的,所以我们,必须切换到托管线程上下文,查看具体的调用栈。先执行【~0s】切换线程,然后再执行【!clrstack】命令,查看具体的调用栈。
  1. 1 0:007> !DumpModule 00007ff913982df0
  2. 2 Name: Unknown Module
  3. 3 <strong>Attributes:              Reflection IsDynamic IsInMemory
  4. </strong> 4 TransientFlags:          00200811
  5. 5 Assembly:                0000024763a92070
  6. 6 BaseAddress:             0000000000000000
  7. 7 PEFile:                  00000247633187B0
  8. 8 ModuleId:                00007FF9139831F0
  9. 9 ModuleIndex:             000000000000076D
  10. 10 LoaderHeap:              00007FF971464588
  11. 11 TypeDefToMethodTableMap: 00007FF91397E100
  12. 12 TypeRefToMethodTableMap: 00007FF91397E128
  13. 13 MethodDefToDescMap:      00007FF91397E1A0
  14. 14 FieldDefToDescMap:       00007FF91397E1F0
  15. 15 MemberRefToDescMap:      00007FF91397E150
  16. 16 FileReferencesMap:       0000000000000000
  17. 17 AssemblyReferencesMap:   00007FF91397E290
复制代码
                  继续执行。            
  1. 1 0:007> ~0s
  2. 2 00007ff9`115d11f3 488b4050        mov     rax,qword ptr [rax+50h] ds:00007ff9`116fe810=00007ff9116fe310
复制代码
                  到这里,我们就很清楚了, System.Xml.Serialization.XmlSerializer..ctor 类型创建了实例,在内部又调用了 System.Xml.Serialization.XmlSerializer.GenerateTempAssembly 创建临时的程序集,问题找到了,剩下的就简单了。
              2)、Windbg Preview 调试
                  编译项目,运行我们的控制台程序:ExampleCore_5_10.exe,等输出的数字大于2000,输出内容如:已经序列化第【XXXX】个人了,XXXX 就是具体的数字,开始打开【Windbg Preview】调试器,依次点击【文件】---【Attach to process】,点击【Attach】附加我们的进程。此时调试器卡死,我们的控制台程序输出也停止了,我们回到调试器中,点击【Break】按钮,就可以调试我们的任务了。
                  此时的输出的内容可能太多,我们可以使用【.cls】命令清理一下调试器的输出。
                  我们先查看一下托管堆的情况,执行命令【!eeheap】。
  1. 1 0:000> !clrstack
  2. 2 OS Thread Id: 0x2420 (0)
  3. 3         Child SP               IP Call Site
  4. 4 0000009BDD97E290 00007ff980bac400 [InlinedCallFrame: 0000009bdd97e290]
  5. 5 0000009BDD97E290 00007ff9735a4500 [InlinedCallFrame: 0000009bdd97e290]
  6. 6 0000009BDD97E260 00007FF9735A4500 System.Reflection.Emit.RuntimeModuleBuilder.GetTypeRefNested(System.Type, System.Reflection.Module)
  7. 7 0000009BDD97E380 00007FF9735A6529 System.Reflection.Emit.RuntimeModuleBuilder.GetTypeTokenWorkerNoLock(System.Type, Boolean)
  8. 8 0000009BDD97E480 00007FF9735A62BF System.Reflection.Emit.RuntimeModuleBuilder.GetTypeTokenInternal(System.Type, Boolean)
  9. 9 0000009BDD97E4E0 00007FF9735A67F4 System.Reflection.Emit.RuntimeModuleBuilder.GetMethodTokenNoLock(System.Reflection.MethodInfo, Boolean)
  10. 10 0000009BDD97E590 00007FF9735A669A System.Reflection.Emit.RuntimeModuleBuilder.GetMethodMetadataToken(System.Reflection.MethodInfo)
  11. 11 0000009BDD97E5F0 00007FF9735A6E68 System.Reflection.Emit.RuntimeModuleBuilder.GetMethodTokenInternal(System.Reflection.MethodBase, System.Type[], Boolean)
  12. 12 0000009BDD97E680 00007FF97359FD59 System.Reflection.Emit.RuntimeILGenerator.EmitCall(System.Reflection.Emit.OpCode, System.Reflection.MethodInfo, System.Type[])
  13. 13 0000009BDD97E700 00007FF97359F724 System.Reflection.Emit.RuntimeILGenerator.Emit(System.Reflection.Emit.OpCode, System.Reflection.MethodInfo)
  14. 14 0000009BDD97E750 00007FF972DA68C3 System.Xml.Serialization.XmlSerializationILGen.GenerateTypedSerializer(System.String, System.String, System.Xml.Serialization.XmlMapping, System.Xml.Serialization.CodeIdentifiers, System.String, System.String, System.String)
  15. 15 0000009BDD97E800 00007FF972D6BD5D System.Xml.Serialization.TempAssembly.GenerateRefEmitAssembly(System.Xml.Serialization.XmlMapping[], System.Type[])
  16. 16 0000009BDD97E970 00007FF972D6AC4C System.Xml.Serialization.TempAssembly..ctor(System.Xml.Serialization.XmlMapping[], System.Type[], System.String, System.String)
  17. 17 0000009BDD97E9E0 00007FF972DE4DCD <strong>System.Xml.Serialization.XmlSerializer.GenerateTempAssembly</strong>(System.Xml.Serialization.XmlMapping, System.Type, System.String, System.String)
  18. 18 0000009BDD97EA40 00007FF972DE4673 <strong>System.Xml.Serialization.XmlSerializer..ctor</strong>(System.Type, System.Xml.Serialization.XmlRootAttribute)
  19. 19 0000009BDD97EA90 00007FF921171B74 ExampleCore_5_10.Program.Run()
  20. 20 0000009BDD97EB50 00007FF921171988 ExampleCore_5_10.Program.Main(System.String[])
复制代码
                  当我看到这个结果的时候,我感觉没有什么异常,除了这应用程序域【Domain 1】,它提示说:No unique loader heaps found. 没有找到唯一的加载堆,说明就是有多个,这个应用程序的地址是:01be298ed190,我们针对这个地址查看一下这个应用程序域的详情,执行命令【!DumpDomain 01be298ed190】。
  1. 1 0:008> !eeheap
  2. 2 Loader Heap:
  3. 3 ----------------------------------------
  4. 4 System Domain:        7ff96f6d40c0
  5. 5 LoaderAllocator:      7ff96f6d40c0
  6. 6 LowFrequencyHeap:     7ff914280000(10000:3000) 7ff914270000(10000:f000) 7ff914260000(10000:f000) 7ff914240000(10000:f000) 7ff914220000(10000:f000) 7ff914210000(10000:f000) 7ff914200000(10000:f000) 7ff9141f0000(10000:f000) 7ff9141e0000(10000:f000) 7ff9141c0000(10000:f000) 7ff9141b0000(10000:f000) 7ff9141a0000(10000:f000) 7ff914190000(10000:f000) 7ff914170000(10000:f000) 7ff914150000(10000:f000) 7ff914140000(10000:f000) 7ff914130000(10000:f000) 7ff914120000(10000:f000) 7ff914100000(10000:f000) 7ff9140f0000(10000:f000) 7ff9140e0000(10000:f000) 7ff9140d0000(10000:f000) 7ff9140c0000(10000:f000) 7ff9140a0000(10000:f000) 7ff914090000(10000:f000) 7ff914080000(10000:f000) 7ff914060000(10000:f000) 7ff914040000(10000:f000) 7ff914030000(10000:f000) 7ff914020000(10000:f000) 7ff914010000(10000:f000) 7ff914000000(10000:f000) 7ff913fe0000(10000:f000) 7ff913fd0000(10000:f000) 7ff913fc0000(10000:f000) 7ff913fb0000(10000:f000) 7ff913fa0000(10000:f000) 7ff913f70000(10000:f000) 7ff913f60000(10000:f000) 7ff913f50000(10000:f000) 7ff913f40000(10000:f000) 7ff913f30000(10000:f000) 7ff913f10000(10000:f000) 7ff913f00000(10000:f000) 7ff913ef0000(10000:f000) 7ff913ee0000(10000:f000) 7ff913ec0000(10000:f000) 7ff913eb0000(10000:f000) 7ff913e90000(10000:f000) 7ff913e80000(10000:f000) 7ff913e70000(10000:f000) 7ff913e50000(10000:f000) 7ff913e40000(10000:f000) 7ff913e30000(10000:f000) 7ff913e20000(10000:f000) 7ff913e10000(10000:f000) 7ff913df0000(10000:f000) 7ff913de0000(10000:f000) 7ff913dd0000(10000:f000) 7ff913dc0000(10000:f000) 7ff913da0000(10000:f000) 7ff913d80000(10000:f000) 7ff913d70000(10000:f000) 7ff913d60000(10000:f000) 7ff913d50000(10000:f000) 7ff913d30000(10000:f000) 7ff913d20000(10000:f000) 7ff913d10000(10000:f000) 7ff913d00000(10000:f000) 7ff913cf0000(10000:f000) 7ff913cd0000(10000:f000) 7ff913cb0000(10000:f000) 7ff913ca0000(10000:f000) 7ff913c90000(10000:f000) 7ff913c80000(10000:f000) 7ff913c60000(10000:f000) 7ff913c50000(10000:f000) 7ff913c40000(10000:f000) 7ff913c30000(10000:f000) 7ff913c20000(10000:f000) 7ff913c00000(10000:f000) 7ff913bf0000(10000:f000) 7ff913bd0000(10000:f000) 7ff913bc0000(10000:f000) 7ff913ba0000(10000:f000) 7ff913b90000(10000:f000) 7ff913b80000(10000:f000) 7ff913b70000(10000:f000) 7ff913b60000(10000:f000) 7ff913b40000(10000:f000) 7ff913b30000(10000:f000) 7ff913b20000(10000:f000) 7ff913b10000(10000:f000) 7ff913b00000(10000:f000) 7ff913ad0000(10000:f000) 7ff913ac0000(10000:f000) 7ff913ab0000(10000:f000) 7ff913aa0000(10000:f000) 7ff913a80000(10000:f000) 7ff913a70000(10000:f000) 7ff913a60000(10000:f000) 7ff913a50000(10000:f000) 7ff913a40000(10000:f000) 7ff913a20000(10000:f000) 7ff913a10000(10000:f000) 7ff9139f0000(10000:f000) 7ff9139e0000(10000:f000) 7ff9139d0000(10000:f000) 7ff9139b0000(10000:f000) 7ff9139a0000(10000:f000) 7ff913990000(10000:f000) 7ff913980000(10000:f000) 7ff913970000(10000:f000) 7ff913950000(10000:f000) 7ff913940000(10000:f000) 7ff913930000(10000:f000) 7ff913910000(10000:f000) 7ff9138f0000(10000:f000) 7ff9138e0000(10000:f000) 7ff9138d0000(10000:f000) 7ff9138c0000(10000:f000) 7ff9138b0000(10000:f000) 7ff913890000(10000:f000) 7ff913880000(10000:f000) 7ff913870000(10000:f000) 7ff913860000(10000:f000) 7ff913850000(10000:f000) 7ff913830000(10000:f000) 7ff913810000(10000:f000) 7ff913800000(10000:f000) 7ff9137f0000(10000:f000) 7ff9137e0000(10000:f000) 7ff9137c0000(10000:f000) 7ff9137b0000(10000:f000) 7ff9137a0000(10000:f000) 7ff913790000(10000:f000) 7ff913770000(10000:f000) 7ff913760000(10000:f000) 7ff913750000(10000:f000) 7ff913730000(10000:f000) 7ff913720000(10000:f000) 7ff913700000(10000:f000) 7ff9136f0000(10000:f000) 7ff9136e0000(10000:f000) 7ff9136d0000(10000:f000) 7ff9136c0000(10000:f000) 7ff9136a0000(10000:f000) 7ff913690000(10000:f000) 7ff913680000(10000:f000) 7ff913670000(10000:f000) 7ff913650000(10000:f000) 7ff913630000(10000:f000) 7ff913620000(10000:f000) 7ff913610000(10000:f000) 7ff913600000(10000:f000) 7ff9135e0000(10000:f000) 7ff9135d0000(10000:f000) 7ff9135c0000(10000:f000) 7ff9135b0000(10000:f000) 7ff9135a0000(10000:f000) 7ff913580000(10000:f000) 7ff913570000(10000:f000) 7ff913550000(10000:f000) 7ff913540000(10000:f000) 7ff913530000(10000:f000) 7ff913510000(10000:f000) 7ff913500000(10000:f000) 7ff9134f0000(10000:f000) 7ff9134e0000(10000:f000) 7ff9134c0000(10000:f000) 7ff9134b0000(10000:f000) 7ff9134a0000(10000:f000) 7ff913490000(10000:f000) 7ff913470000(10000:f000) 7ff913450000(10000:f000) 7ff913440000(10000:f000) 7ff913430000(10000:f000) 7ff913420000(10000:f000) 7ff913410000(10000:f000) 7ff9133f0000(10000:f000) 7ff9133e0000(10000:f000) 7ff9133d0000(10000:f000) 7ff9133c0000(10000:f000) 7ff9133b0000(10000:f000) 7ff913380000(10000:f000) 7ff913370000(10000:f000) 7ff913360000(10000:f000) 7ff913350000(10000:f000) 7ff913330000(10000:f000) 7ff913320000(10000:f000) 7ff913310000(10000:f000) 7ff913300000(10000:f000) 7ff9132f0000(10000:f000) 7ff9132d0000(10000:f000) 7ff9132c0000(10000:f000) 7ff9132b0000(10000:f000) 7ff913290000(10000:f000) 7ff913280000(10000:f000) 7ff913260000(10000:f000) 7ff913250000(10000:f000) 7ff913240000(10000:f000) 7ff913230000(10000:f000) 7ff913220000(10000:f000) 7ff913200000(10000:f000) 7ff9131f0000(10000:f000) 7ff9131e0000(10000:f000) 7ff9131d0000(10000:f000) 7ff9131a0000(10000:f000) 7ff913190000(10000:f000) 7ff913180000(10000:f000) 7ff913170000(10000:f000) 7ff913160000(10000:f000) 7ff913140000(10000:f000) 7ff913130000(10000:f000) 7ff913120000(10000:f000) 7ff913110000(10000:f000) 7ff913100000(10000:f000) 7ff9130e0000(10000:f000) 7ff9130c0000(10000:f000) 7ff9130b0000(10000:f000) 7ff9130a0000(10000:f000) 7ff913080000(10000:f000) 7ff913070000(10000:10000) 7ff912e60000(10000:e000) 7ff912e50000(10000:f000) 7ff912e40000(10000:f000) 7ff912e30000(10000:f000) 7ff912e10000(10000:f000) 7ff912e00000(10000:f000) 7ff912df0000(10000:f000) 7ff912dd0000(10000:f000) 7ff912db0000(10000:f000) 7ff912da0000(10000:f000) 7ff912d90000(10000:f000) 7ff912d80000(10000:f000) 7ff912d70000(10000:f000) 7ff912d50000(10000:f000) 7ff912d40000(10000:f000) 7ff912d30000(10000:f000) 7ff912d20000(10000:f000) 7ff912d10000(10000:f000) 7ff912ce0000(10000:f000) 7ff912cd0000(10000:f000) 7ff912cc0000(10000:f000) 7ff912cb0000(10000:f000) 7ff912ca0000(10000:f000) 7ff912c80000(10000:f000) 7ff912c70000(10000:f000) 7ff912c60000(10000:f000) 7ff912c50000(10000:f000) 7ff912c30000(10000:f000) 7ff912c20000(10000:f000) 7ff912c10000(10000:f000) 7ff912bf0000(10000:f000) 7ff912be0000(10000:f000) 7ff912bc0000(10000:f000) 7ff912bb0000(10000:f000) 7ff912ba0000(10000:f000) 7ff912b90000(10000:f000) 7ff912b80000(10000:f000) 7ff912b60000(10000:f000) 7ff912b50000(10000:f000) 7ff912b40000(10000:f000) 7ff912b30000(10000:f000) 7ff912b10000(10000:f000) 7ff912af0000(10000:f000) 7ff912ae0000(10000:f000) 7ff912ad0000(10000:f000) 7ff912ac0000(10000:f000) 7ff912aa0000(10000:f000) 7ff912a90000(10000:f000) 7ff912a80000(10000:f000) 7ff912a70000(10000:f000) 7ff912a60000(10000:f000) 7ff912a40000(10000:f000) 7ff912a20000(10000:f000) 7ff912a10000(10000:f000) 7ff912a00000(10000:f000) 7ff9129f0000(10000:f000) 7ff9129d0000(10000:f000) 7ff9129c0000(10000:f000) 7ff9129b0000(10000:f000) 7ff9129a0000(10000:f000) 7ff912980000(10000:f000) 7ff912970000(10000:f000) 7ff912960000(10000:f000) 7ff912950000(10000:f000) 7ff912930000(10000:f000) 7ff912910000(10000:f000) 7ff912900000(10000:f000) 7ff9128f0000(10000:f000) 7ff9128e0000(10000:f000) 7ff9128d0000(10000:f000) 7ff9128b0000(10000:f000) 7ff9128a0000(10000:f000) 7ff912890000(10000:f000) 7ff912880000(10000:f000) 7ff912870000(10000:f000) 7ff912840000(10000:f000) 7ff912830000(10000:f000) 7ff912820000(10000:f000) 7ff912810000(10000:f000) 7ff9127f0000(10000:f000) 7ff9127e0000(10000:f000) 7ff9127d0000(10000:f000) 7ff9127c0000(10000:f000) 7ff9127b0000(10000:f000) 7ff912790000(10000:f000) 7ff912780000(10000:f000) 7ff912760000(10000:f000) 7ff912750000(10000:f000) 7ff912740000(10000:f000) 7ff912720000(10000:f000) 7ff912710000(10000:f000) 7ff912700000(10000:f000) 7ff9126f0000(10000:f000) 7ff9126e0000(10000:f000) 7ff9126c0000(10000:f000) 7ff9126b0000(10000:f000) 7ff9126a0000(10000:f000) 7ff912690000(10000:f000) 7ff912660000(10000:f000) 7ff912650000(10000:f000) 7ff912640000(10000:f000) 7ff9125b0000(10000:10000) 7ff9125a0000(10000:f000) 7ff912580000(10000:f000) 7ff912570000(10000:f000) 7ff912560000(10000:f000) 7ff912550000(10000:f000) 7ff912540000(10000:f000) 7ff912520000(10000:f000) 7ff912500000(10000:f000) 7ff9124f0000(10000:f000) 7ff9124e0000(10000:f000) 7ff9124d0000(10000:f000) 7ff9124b0000(10000:f000) 7ff9124a0000(10000:f000) 7ff912490000(10000:f000) 7ff912480000(10000:f000) 7ff912460000(10000:f000) 7ff912450000(10000:f000) 7ff912440000(10000:f000) 7ff912420000(10000:f000) 7ff912410000(10000:f000) 7ff9123f0000(10000:f000) 7ff9123e0000(10000:f000) 7ff9123d0000(10000:f000) 7ff9123c0000(10000:f000) 7ff9123b0000(10000:f000) 7ff912390000(10000:f000) 7ff912380000(10000:f000) 7ff912370000(10000:f000) 7ff912360000(10000:f000) 7ff912340000(10000:f000) 7ff912320000(10000:f000) 7ff912310000(10000:f000) 7ff912300000(10000:f000) 7ff9122f0000(10000:f000) 7ff9122d0000(10000:f000) 7ff9122c0000(10000:f000) 7ff9122b0000(10000:f000) 7ff9122a0000(10000:f000) 7ff912290000(10000:f000) 7ff912270000(10000:f000) 7ff912260000(10000:f000) 7ff912240000(10000:f000) 7ff912230000(10000:f000) 7ff912220000(10000:f000) 7ff912200000(10000:f000) 7ff9121f0000(10000:f000) 7ff9121e0000(10000:f000) 7ff9121d0000(10000:f000) 7ff9121b0000(10000:f000) 7ff9121a0000(10000:f000) 7ff912190000(10000:f000) 7ff912180000(10000:f000) 7ff912160000(10000:f000) 7ff912140000(10000:f000) 7ff912130000(10000:f000) 7ff912120000(10000:f000) 7ff912110000(10000:f000) 7ff912100000(10000:f000) 7ff9120e0000(10000:f000) 7ff9120d0000(10000:f000) 7ff9120c0000(10000:f000) 7ff9120b0000(10000:f000) 7ff9120a0000(10000:f000) 7ff912080000(10000:f000) 7ff912060000(10000:f000) 7ff912050000(10000:f000) 7ff912040000(10000:f000) 7ff912020000(10000:f000) 7ff912010000(10000:f000) 7ff912000000(10000:f000) 7ff911ff0000(10000:f000) 7ff911fe0000(10000:f000) 7ff911fc0000(10000:f000) 7ff911fb0000(10000:f000) 7ff911fa0000(10000:f000) 7ff911f80000(10000:f000) 7ff911f70000(10000:f000) 7ff911f50000(10000:f000) 7ff911f40000(10000:f000) 7ff911f30000(10000:f000) 7ff911f20000(10000:f000) 7ff911f10000(10000:f000) 7ff911ef0000(10000:f000) 7ff911ee0000(10000:f000) 7ff911ed0000(10000:f000) 7ff911ec0000(10000:f000) 7ff911e90000(10000:f000) 7ff911e80000(10000:f000) 7ff911e70000(10000:f000) 7ff911e60000(10000:f000) 7ff911e50000(10000:f000) 7ff911e30000(10000:f000) 7ff911e20000(10000:f000) 7ff911e10000(10000:f000) 7ff911e00000(10000:f000) 7ff911df0000(10000:f000) 7ff911dd0000(10000:f000) 7ff911dc0000(10000:f000) 7ff911da0000(10000:f000) 7ff911d90000(10000:f000) 7ff911cf0000(10000:10000) 7ff911ce0000(10000:f000) 7ff911cd0000(10000:f000) 7ff911cc0000(10000:f000) 7ff911cb0000(10000:f000) 7ff911c90000(10000:f000) 7ff911c80000(10000:f000) 7ff911c70000(10000:f000) 7ff911c60000(10000:f000) 7ff911c40000(10000:f000) 7ff911c20000(10000:f000) 7ff911c10000(10000:f000) 7ff911c00000(10000:f000) 7ff911bf0000(10000:f000) 7ff911be0000(10000:f000) 7ff911bc0000(10000:f000) 7ff911bb0000(10000:f000) 7ff911ba0000(10000:f000) 7ff911b90000(10000:f000) 7ff911b70000(10000:f000) 7ff911b50000(10000:f000) 7ff911b40000(10000:f000) 7ff911b30000(10000:f000) 7ff911b20000(10000:f000) 7ff911b00000(10000:f000) 7ff911af0000(10000:f000) 7ff911ae0000(10000:f000) 7ff911ad0000(10000:f000) 7ff911ac0000(10000:f000) 7ff911aa0000(10000:f000) 7ff911a90000(10000:f000) 7ff911a80000(10000:f000) 7ff911a60000(10000:f000) 7ff911a50000(10000:f000) 7ff911a30000(10000:f000) 7ff911a20000(10000:f000) 7ff911a10000(10000:f000) 7ff911a00000(10000:f000) 7ff9119e0000(10000:f000) 7ff9119d0000(10000:f000) 7ff9119c0000(10000:f000) 7ff9119b0000(10000:f000) 7ff9119a0000(10000:f000) 7ff911970000(10000:f000) 7ff911960000(10000:f000) 7ff911950000(10000:f000) 7ff911940000(10000:f000) 7ff911930000(10000:f000) 7ff911910000(10000:f000) 7ff911900000(10000:f000) 7ff9118f0000(10000:f000) 7ff9118e0000(10000:f000) 7ff9118d0000(10000:f000) 7ff9118b0000(10000:f000) 7ff911890000(10000:f000) 7ff911880000(10000:f000) 7ff911870000(10000:f000) 7ff911850000(10000:f000) 7ff911840000(10000:f000) 7ff911830000(10000:f000) 7ff911820000(10000:f000) 7ff911810000(10000:f000) 7ff9117f0000(10000:f000) 7ff9117e0000(10000:f000) 7ff9117d0000(10000:f000) 7ff9117c0000(10000:f000) 7ff9117a0000(10000:f000) 7ff911780000(10000:f000) 7ff911770000(10000:f000) 7ff911760000(10000:f000) 7ff911750000(10000:f000) 7ff911730000(10000:f000) 7ff911720000(10000:f000) 7ff911710000(10000:f000) 7ff911700000(10000:f000) 7ff9116f0000(10000:f000) 7ff9116d0000(10000:f000) 7ff9116b0000(10000:f000) 7ff9116a0000(10000:f000) 7ff911690000(10000:f000) 7ff911680000(10000:f000) 7ff911660000(10000:f000) 7ff911650000(10000:f000) 7ff911640000(10000:f000) 7ff911630000(10000:f000) 7ff911620000(10000:f000) 7ff911600000(10000:f000) 7ff9115f0000(10000:f000) 7ff9115d0000(10000:f000) 7ff9115c0000(10000:f000) 7ff9115a0000(10000:f000) 7ff911590000(10000:f000) 7ff911580000(10000:f000) 7ff911570000(10000:f000) 7ff911560000(10000:f000) 7ff911540000(10000:f000) 7ff911530000(10000:f000) 7ff911520000(10000:f000) 7ff911510000(10000:f000) 7ff911500000(10000:f000) 7ff9114d0000(10000:f000) 7ff9114c0000(10000:f000) 7ff911430000(10000:10000) 7ff911420000(10000:f000) 7ff911410000(10000:f000) 7ff9113f0000(10000:f000) 7ff9113e0000(10000:f000) 7ff9113d0000(10000:f000) 7ff9113c0000(10000:f000) 7ff9113a0000(10000:f000) 7ff911390000(10000:f000) 7ff911370000(10000:f000) 7ff911360000(10000:f000) 7ff911350000(10000:f000) 7ff911330000(10000:f000) 7ff911320000(10000:f000) 7ff911310000(10000:f000) 7ff911300000(10000:f000) 7ff9112f0000(10000:f000) 7ff9112d0000(10000:f000) 7ff9112c0000(10000:f000) 7ff9112b0000(10000:f000) 7ff911290000(10000:f000) 7ff911280000(10000:f000) 7ff911260000(10000:f000) 7ff911250000(10000:f000) 7ff911240000(10000:f000) 7ff911230000(10000:f000) 7ff911210000(10000:f000) 7ff911200000(10000:f000) 7ff9111f0000(10000:f000) 7ff9111e0000(10000:f000) 7ff9111d0000(10000:f000) 7ff9111b0000(10000:f000) 7ff911190000(10000:f000) 7ff911180000(10000:f000) 7ff911170000(10000:f000) 7ff911160000(10000:f000) 7ff911140000(10000:f000) 7ff911130000(10000:f000) 7ff911120000(10000:f000) 7ff911110000(10000:f000) 7ff9110f0000(10000:f000) 7ff9110e0000(10000:f000) 7ff9110d0000(10000:f000) 7ff9110b0000(10000:f000) 7ff9110a0000(10000:f000) 7ff911080000(10000:f000) 7ff911070000(10000:f000) 7ff911060000(10000:f000) 7ff911050000(10000:f000) 7ff911040000(10000:f000) 7ff911020000(10000:f000) 7ff911010000(10000:f000) 7ff911000000(10000:f000) 7ff910ff0000(10000:f000) 7ff910fd0000(10000:f000) 7ff910fb0000(10000:f000) 7ff910fa0000(10000:f000) 7ff910f90000(10000:f000) 7ff910f80000(10000:f000) 7ff910f60000(10000:f000) 7ff910f50000(10000:f000) 7ff910f40000(10000:f000) 7ff910f30000(10000:f000) 7ff910f20000(10000:f000) 7ff910f00000(10000:f000) 7ff910ef0000(10000:f000) 7ff910ed0000(10000:f000) 7ff910ec0000(10000:f000) 7ff910eb0000(10000:f000) 7ff910e90000(10000:f000) 7ff910e80000(10000:f000) 7ff910e70000(10000:f000) 7ff910e60000(10000:f000) 7ff910e50000(10000:f000) 7ff910e30000(10000:f000) 7ff910e20000(10000:f000) 7ff910e10000(10000:f000) 7ff910df0000(10000:f000) 7ff910dd0000(10000:f000) 7ff910dc0000(10000:f000) 7ff910db0000(10000:f000) 7ff910da0000(10000:f000) 7ff910d90000(10000:f000) 7ff910d70000(10000:f000) 7ff910d60000(10000:f000) 7ff910d50000(10000:f000) 7ff910d40000(10000:f000) 7ff910d30000(10000:f000) 7ff910d00000(10000:f000) 7ff910cf0000(10000:f000) 7ff910ce0000(10000:f000) 7ff910cd0000(10000:f000) 7ff910cc0000(10000:f000) 7ff910ca0000(10000:f000) 7ff910c90000(10000:f000) 7ff910c80000(10000:f000) 7ff910c70000(10000:f000) 7ff910c50000(10000:f000) 7ff910c40000(10000:f000) 7ff910c30000(10000:f000) 7ff910c10000(10000:f000) 7ff910b80000(10000:10000) 7ff910b60000(10000:f000) 7ff910b50000(10000:f000) 7ff910b40000(10000:f000) 7ff910b30000(10000:f000) 7ff910b20000(10000:f000) 7ff910b00000(10000:f000) 7ff910af0000(10000:f000) 7ff910ae0000(10000:f000) 7ff910ad0000(10000:f000) 7ff910aa0000(10000:f000) 7ff910a90000(10000:f000) 7ff910a80000(10000:f000) 7ff910a70000(10000:f000) 7ff910a60000(10000:f000) 7ff910a40000(10000:f000) 7ff910a30000(10000:f000) 7ff910a20000(10000:f000) 7ff910a10000(10000:f000) 7ff910a00000(10000:f000) 7ff9109e0000(10000:f000) 7ff9109c0000(10000:f000) 7ff9109b0000(10000:f000) 7ff9109a0000(10000:f000) 7ff910990000(10000:f000) 7ff910970000(10000:f000) 7ff910HighFrequencyHeap:    7ff914230000(10000:c000) 7ff9141d0000(10000:10000) 7ff914180000(10000:10000) 7ff914110000(10000:10000) 7ff9140b0000(10000:10000) 7ff914050000(10000:10000) 7ff913ff0000(10000:10000) 7ff913f90000(10000:10000) 7ff913f20000(10000:10000) 7ff913ed0000(10000:10000) 7ff913e60000(10000:10000) 7ff913e00000(10000:10000) 7ff913d90000(10000:10000) 7ff913d40000(10000:10000) 7ff913ce0000(10000:10000) 7ff913c70000(10000:10000) 7ff913c10000(10000:10000) 7ff913bb0000(10000:10000) 7ff913b50000(10000:10000) 7ff913ae0000(10000:10000) 7ff913a90000(10000:10000) 7ff913a30000(10000:10000) 7ff9139c0000(10000:10000) 7ff913960000(10000:10000) 7ff913900000(10000:10000) 7ff9138a0000(10000:10000) 7ff913840000(10000:10000) 7ff9137d0000(10000:10000) 7ff913780000(10000:10000) 7ff913710000(10000:10000) 7ff9136b0000(10000:10000) 7ff913640000(10000:10000) 7ff9135f0000(10000:10000) 7ff913590000(10000:10000) 7ff913520000(10000:10000) 7ff9134d0000(10000:10000) 7ff913460000(10000:10000) 7ff913400000(10000:10000) 7ff9133a0000(10000:10000) 7ff913340000(10000:10000) 7ff9132e0000(10000:10000) 7ff913270000(10000:10000) 7ff913210000(10000:10000) 7ff9131b0000(10000:10000) 7ff913150000(10000:10000) 7ff9130f0000(10000:10000) 7ff913090000(10000:10000) 7ff912e20000(10000:10000) 7ff912dc0000(10000:10000) 7ff912d60000(10000:10000) 7ff912d00000(10000:10000) 7ff912c90000(10000:10000) 7ff912c40000(10000:10000) 7ff912bd0000(10000:10000) 7ff912b70000(10000:10000) 7ff912b00000(10000:10000) 7ff912ab0000(10000:10000) 7ff912a50000(10000:10000) 7ff9129e0000(10000:10000) 7ff912990000(10000:10000) 7ff912920000(10000:10000) 7ff9128c0000(10000:10000) 7ff912860000(10000:10000) 7ff912800000(10000:10000) 7ff9127a0000(10000:10000) 7ff912730000(10000:10000) 7ff9126d0000(10000:10000) 7ff912670000(10000:10000) 7ff912590000(10000:10000) 7ff912530000(10000:10000) 7ff9124c0000(10000:10000) 7ff912470000(10000:10000) 7ff912400000(10000:10000) 7ff9123a0000(10000:10000) 7ff912350000(10000:10000) 7ff9122e0000(10000:10000) 7ff912280000(10000:10000) 7ff912210000(10000:10000) 7ff9121c0000(10000:10000) 7ff912150000(10000:10000) 7ff9120f0000(10000:10000) 7ff912090000(10000:10000) 7ff912030000(10000:10000) 7ff911fd0000(10000:10000) 7ff911f60000(10000:10000) 7ff911f00000(10000:10000) 7ff911eb0000(10000:10000) 7ff911e40000(10000:10000) 7ff911de0000(10000:10000) 7ff911d00000(10000:10000) 7ff911ca0000(10000:10000) 7ff911c30000(10000:10000) 7ff911bd0000(10000:10000) 7ff911b80000(10000:10000) 7ff911b10000(10000:10000) 7ff911ab0000(10000:10000) 7ff911a40000(10000:10000) 7ff9119f0000(10000:10000) 7ff911980000(10000:10000) 7ff911920000(10000:10000) 7ff9118c0000(10000:10000) 7ff911860000(10000:10000) 7ff911800000(10000:10000) 7ff911790000(10000:10000) 7ff911740000(10000:10000) 7ff9116e0000(10000:10000) 7ff911670000(10000:10000) 7ff911610000(10000:10000) 7ff9115b0000(10000:10000) 7ff911550000(10000:10000) 7ff9114e0000(10000:10000) 7ff911400000(10000:10000) 7ff9113b0000(10000:10000) 7ff911340000(10000:10000) 7ff9112e0000(10000:10000) 7ff911270000(10000:10000) 7ff911220000(10000:10000) 7ff9111c0000(10000:10000) 7ff911150000(10000:10000) 7ff911100000(10000:10000) 7ff911090000(10000:10000) 7ff911030000(10000:10000) 7ff910fc0000(10000:10000) 7ff910f70000(10000:10000) 7ff910f10000(10000:10000) 7ff910ea0000(10000:10000) 7ff910e40000(10000:10000) 7ff910de0000(10000:10000) 7ff910d80000(10000:10000) 7ff910d20000(10000:10000) 7ff910cb0000(10000:10000) 7ff910c60000(10000:10000) 7ff910b70000(10000:10000) 7ff910b10000(10000:10000) 7ff910ab0000(10000:10000) 7ff910a50000(10000:10000) 7ff9109f0000(10000:10000) 7ff910980000(10000:10000) 7ff910930000(10000:10000) 7ff9108c0000(10000:10000) 7ff910860000(10000:10000) 7ff910800000(10000:10000) 7ff9107a0000(10000:10000) 7ff910740000(10000:10000) 7ff9106d0000(10000:10000) 7ff910670000(10000:10000) 7ff910610000(10000:10000) 7ff9105b0000(10000:10000) 7ff910550000(10000:10000) 7ff9104f0000(10000:10000) 7ff910490000(10000:10000) 7ff910420000(10000:10000) 7ff9103c0000(10000:10000) 7ff910370000(10000:10000) 7ff910280000(10000:10000) 7ff910220000(10000:10000) 7ff9101b0000(10000:10000) 7ff910160000(10000:10000) 7ff9100f0000(10000:10000) 7ff910090000(10000:10000) 7ff910030000(10000:10000) 7ff90ffd0000(10000:10000) 7ff90ff70000(10000:10000) 7ff90ff00000(10000:10000) 7ff90feb0000(10000:10000) 7ff90fe50000(10000:10000) 7ff90fde0000(10000:10000) 7ff90fd80000(10000:10000) 7ff90fd20000(10000:10000) 7ff90fcc0000(10000:10000) 7ff90fc50000(10000:10000) 7ff90fbf0000(10000:10000) 7ff90fba0000(10000:10000) 7ff90fb50000(10000:10000) 7ff90fb30000(10000:10000) 7ff90fb00000(10000:10000) 7ff90fae0000(10000:10000) 7ff90fab0000(10000:10000) 7ff90fa90000(10000:10000) 7ff90fa70000(10000:10000) 7ff90fa40000(10000:10000) 7ff90fa20000(10000:10000) 7ff90fa00000(10000:10000) 7ff90f9e0000(10000:10000) 7ff90f9b0000(10000:10000) 7ff90f980000(10000:10000) 7ff90f960000(10000:10000) 7ff90f8f0000(10000:f000) 7ff90f8c0000(10000:10000) 7ff90f820000(10000:10000) 7ff90f7f0000(10000:10000) 7ff90f7d0000(10000:10000) 7ff90f7b0000(10000:10000) 7ff90f770000(10000:10000) 7ff90f6e4000(9000:6000) Size: 0xc21000 (12718080) bytes total, 0x4000 (16384) bytes wasted.
  7. 7 StubHeap:             7ff90f6ed000(3000:1000) Size: 0x1000 (4096) bytes total.
  8. 8 FixupPrecodeHeap:     7ff914250000(10000:8000) 7ff914160000(10000:10000) 7ff914070000(10000:10000) 7ff913f80000(10000:10000) 7ff913ea0000(10000:10000) 7ff913db0000(10000:10000) 7ff913cc0000(10000:10000) 7ff913be0000(10000:10000) 7ff913af0000(10000:10000) 7ff913a00000(10000:10000) 7ff913920000(10000:10000) 7ff913820000(10000:10000) 7ff913740000(10000:10000) 7ff913660000(10000:10000) 7ff913560000(10000:10000) 7ff913480000(10000:10000) 7ff913390000(10000:10000) 7ff9132a0000(10000:10000) 7ff9131c0000(10000:10000) 7ff9130d0000(10000:10000) 7ff912de0000(10000:10000) 7ff912cf0000(10000:10000) 7ff912c00000(10000:10000) 7ff912b20000(10000:10000) 7ff912a30000(10000:10000) 7ff912940000(10000:10000) 7ff912850000(10000:10000) 7ff912770000(10000:10000) 7ff912680000(10000:10000) 7ff912510000(10000:10000) 7ff912430000(10000:10000) 7ff912330000(10000:10000) 7ff912250000(10000:10000) 7ff912170000(10000:10000) 7ff912070000(10000:10000) 7ff911f90000(10000:10000) 7ff911ea0000(10000:10000) 7ff911db0000(10000:10000) 7ff911c50000(10000:10000) 7ff911b60000(10000:10000) 7ff911a70000(10000:10000) 7ff911990000(10000:10000) 7ff9118a0000(10000:10000) 7ff9117b0000(10000:10000) 7ff9116c0000(10000:10000) 7ff9115e0000(10000:10000) 7ff9114f0000(10000:10000) 7ff911380000(10000:10000) 7ff9112a0000(10000:10000) 7ff9111a0000(10000:10000) 7ff9110c0000(10000:10000) 7ff910fe0000(10000:10000) 7ff910ee0000(10000:10000) 7ff910e00000(10000:10000) 7ff910d10000(10000:10000) 7ff910c20000(10000:10000) 7ff910ac0000(10000:10000) 7ff9109d0000(10000:10000) 7ff9108e0000(10000:10000) 7ff9107f0000(10000:10000) 7ff910710000(10000:10000) 7ff910620000(10000:10000) 7ff910530000(10000:10000) 7ff910450000(10000:10000) 7ff910350000(10000:10000) 7ff9101f0000(10000:10000) 7ff910110000(10000:10000) 7ff910010000(10000:10000) 7ff90ff30000(10000:10000) 7ff90fe40000(10000:10000) 7ff90fd50000(10000:10000) 7ff90fc70000(10000:10000) 7ff90fb80000(10000:10000) 7ff90fb40000(10000:10000) 7ff90fb20000(10000:10000) 7ff90fb10000(10000:10000) 7ff90faf0000(10000:10000) 7ff90fac0000(10000:10000) 7ff90fa80000(10000:10000) 7ff90fa50000(10000:10000) 7ff90fa30000(10000:10000) 7ff90f9f0000(10000:10000) 7ff90f9d0000(10000:10000) 7ff90f9a0000(10000:10000) 7ff90f990000(10000:10000) 7ff90f910000(10000:10000) 7ff90f8e0000(10000:10000) 7ff90f830000(10000:10000) 7ff90f810000(10000:10000) 7ff90f7e0000(10000:10000) 7ff90f7c0000(10000:10000) 7ff90f780000(10000:10000) Size: 0x5b8000 (5996544) bytes total.
  9. 9 NewStubPrecodeHeap:   7ff90fb60000(10000:8000) 7ff90f790000(10000:10000) Size: 0x18000 (98304) bytes total.
  10. 10 IndirectionCellHeap:  7ff90f6f0000(6000:1000) Size: 0x1000 (4096) bytes total.
  11. 11 CacheEntryHeap:       7ff90f6f6000(a000:1000) Size: 0x1000 (4096) bytes total.
  12. 12 Total size:           Size: 0x4340000 (70516736) bytes total, 0x33e000 (3399680) bytes wasted.
  13. 13 ----------------------------------------
  14. 14 Domain 1:             01be298ed190
  15. 15 LoaderAllocator:      01be298ed190
  16. 16 <strong>No unique loader heaps found.
  17. </strong>17 ----------------------------------------
  18. 18 JIT Manager:          01be2992cb30
  19. 19 LoaderCodeHeap:       7ff90f840000(80000:77000) Size: 0x77000 (487424) bytes total.
  20. 20 LoaderCodeHeap:       7ff9102d0000(80000:7f000) Size: 0x7f000 (520192) bytes total.
  21. 21 LoaderCodeHeap:       7ff910b90000(80000:7f000) Size: 0x7f000 (520192) bytes total.
  22. 22 LoaderCodeHeap:       7ff911440000(80000:7f000) Size: 0x7f000 (520192) bytes total.
  23. 23 LoaderCodeHeap:       7ff911d10000(80000:7f000) Size: 0x7f000 (520192) bytes total.
  24. 24 LoaderCodeHeap:       7ff9125c0000(80000:7f000) Size: 0x7f000 (520192) bytes total.
  25. 25 LoaderCodeHeap:       7ff912e70000(200000:116000) Size: 0x116000 (1138688) bytes total.
  26. 26 Total size:           Size: 0x408000 (4227072) bytes total.
  27. 27 ----------------------------------------
  28. 28
  29. 29 ========================================
  30. 30 Number of GC Heaps: 1
  31. 31 ----------------------------------------
  32. 32 Small object heap
  33. 33          segment            begin        allocated        committed allocated size     committed size   
  34. 34 generation 0:
  35. 35     01fe3f44f320     01be2e000028     01be2e120128     01be2e361000 0x120100 (1179904) 0x361000 (3543040)
  36. 36 generation 1:
  37. 37     01fe3f44f270     01be2dc00028     01be2dc0da38     01be2dc51000 0xda10 (55824)     0x51000 (331776)  
  38. 38 generation 2:
  39. 39     01fe3f44f1c0     01be2d800028     01be2d89ac20     01be2d8a1000 0x9abf8 (633848)   0xa1000 (659456)  
  40. 40 NonGC heap
  41. 41          segment            begin        allocated        committed allocated size     committed size   
  42. 42     01be2992eee0     01febff50008     01fec0023d90     01fec0030000 0xd3d88 (867720)   0xe0000 (917504)  
  43. 43 Large object heap
  44. 44          segment            begin        allocated        committed allocated size     committed size   
  45. 45     01fe3f44f3d0     01be2e400028     01be2e400028     01be2e401000                    0x1000 (4096)     
  46. 46 Pinned object heap
  47. 47          segment            begin        allocated        committed allocated size     committed size   
  48. 48     01fe3f44ec40     01be2b800028     01be2b823e78     01be2b831000 0x23e50 (147024)   0x31000 (200704)  
  49. 49 ------------------------------
  50. 50 GC Allocated Heap Size:    Size: 0x2c02e0 (2884320) bytes.
  51. 51 GC Committed Heap Size:    Size: 0x565000 (5656576) bytes.
  52. 52
  53. 53 Total bytes consumed by CLR: 0x4cad000 (80400384)
复制代码
                  我们看到了吧,红色的部分,我省略了很多,如果全部输出,太多了。从表面上看,也能猜到有问题。在我们应用程序域中加载了很多动态创建的程序集,就是这个东西导致的内存泄漏。
                  我们以最后一个为例,模块的类型也是【Dynamic Module】,地址是:00007ff91423af50,我们再使用【!DumpModule 00007ff91423af50】命令,查看一下这个模块的信息。
  1.   1 0:008> !DumpDomain 01be298ed190
  2.   2 --------------------------------------
  3.   3 Domain 1:           000001be298ed190
  4.   4 LowFrequencyHeap:   00007FF96F6D4598
  5.   5 HighFrequencyHeap:  00007FF96F6D4628
  6.   6 StubHeap:           00007FF96F6D46B8
  7.   7 Stage:              OPEN
  8.   8 Name:               clrhost
  9.   9 Assembly:           000001be29925af0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll]
  10. 10 ClassLoader:        000001BE298F0130
  11. 11   Module
  12. 12   00007ff90f6e4000    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll
  13. 13
  14. 14 Assembly:           000001be29925550 [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_10\bin\Debug\net8.0\ExampleCore_5_10.dll]
  15. 15 ClassLoader:        000001BE299B7E30
  16. 16   Module
  17. 17   00007ff90f8ce0a0    E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_5_10\bin\Debug\net8.0\ExampleCore_5_10.dll
  18. 18
  19. 19 Assembly:           000001be29925610 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Runtime.dll]
  20. 20 ClassLoader:        000001BE299B7B70
  21. 21   Module
  22. 22   00007ff90f8cfbc8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Runtime.dll
  23. 23
  24. 24 ......(太多了,省略了)
  25. 25
  26. 26 Assembly:           000001fec03845c0 (Dynamic) []
  27. 27 ClassLoader:        000001BE2B3E8360
  28. 28   Module
  29. 29   00007ff90fb5acf8    Dynamic Module
  30. 30
  31. 31 Assembly:           000001fec0384560 (Dynamic) []
  32. 32 ClassLoader:        000001BE2B3E9D80
  33. 33   Module
  34. 34   00007ff90fb5b7c0    Dynamic Module
  35. 35
  36. 36 Assembly:           000001fec0385040 (Dynamic) []
  37. 37 ClassLoader:        000001BE2B3E8D00
  38. 38   Module
  39. 39   00007ff90fb5c288    Dynamic Module
  40. 40
  41. 41 Assembly:           000001fec0384bc0 (Dynamic) []
  42. 42 ClassLoader:        000001BE2B3E7F40
  43. 43   Module
  44. 44   00007ff90fb5cd50    Dynamic Module
  45. 45
  46. 46 ......(太多了,省略了)
  47. 47
  48. 48 Assembly:           000001fec49d52d0 (Dynamic) []
  49. 49 ClassLoader:        000001FEC470FD30
  50. 50   Module
  51. 51   00007ff910f76ea0    Dynamic Module
  52. 52
  53. 53 Assembly:           000001fec49d5690 (Dynamic) []
  54. 54 ClassLoader:        000001FEC47106D0
  55. 55   Module
  56. 56   00007ff910f77968    Dynamic Module
  57. 57
  58. 58 Assembly:           000001fec49d4eb0 (Dynamic) []
  59. 59 ClassLoader:        000001FEC47102B0
  60. 60   Module
  61. 61   00007ff910f78430    Dynamic Module
  62. 62
  63. 63 Assembly:           000001fec49d4970 (Dynamic) []
  64. 64 ClassLoader:        000001FEC4710830
  65. 65   Module
  66. 66   00007ff910f78ef8    Dynamic Module
  67. 67
  68. 68 Assembly:           000001fec49d6ef0 (Dynamic) []
  69. 69 ClassLoader:        000001FEC4710620
  70. 70   Module
  71. 71   00007ff910f799c0    Dynamic Module
  72. 72
  73. 73 ......(太多了,省略了)
  74. 74
  75. 75 Assembly:           000001fec78939e0 (Dynamic) []
  76. 76 ClassLoader:        000001FEC710CF30
  77. 77   Module
  78. 78   00007ff9126d4380    Dynamic Module
  79. 79
  80. 80 Assembly:           000001fec7f35620 (Dynamic) []
  81. 81 ClassLoader:        000001FEC710CB10
  82. 82   Module
  83. 83   00007ff9126d4e48    Dynamic Module
  84. 84
  85. 85 Assembly:           000001fec7f356e0 (Dynamic) []
  86. 86 ClassLoader:        000001FEC710CE80
  87. 87   Module
  88. 88   00007ff9126d5910    Dynamic Module
  89. 89
  90. 90 Assembly:           000001fec7f35380 (Dynamic) []
  91. 91 ClassLoader:        000001FEC710D090
  92. 92   Module
  93. 93   00007ff9126d63d8    Dynamic Module
  94. 94
  95. 95 Assembly:           000001fec7f342a0 (Dynamic) []
  96. 96 ClassLoader:        000001FEC710D140
  97. 97   Module
  98. 98   00007ff9126d6ea0    Dynamic Module
  99. 99
  100. 100 Assembly:           000001fec7f350e0 (Dynamic) []
  101. 101 ClassLoader:        000001FEC710D1F0
  102. 102   Module
  103. 103   00007ff9126d7968    Dynamic Module
  104. 104
  105. 105 Assembly:           000001fec7f34960 (Dynamic) []
  106. 106 ClassLoader:        000001FEC710D2A0
  107. 107   Module
  108. 108   00007ff9126d8430    Dynamic Module
  109. 109
  110. 110 ......(太多了,省略了)
  111. 111
  112. 112 Assembly:           000001fecb90c5c0 (Dynamic) []
  113. 113 ClassLoader:        000001FECA8B0EF0
  114. 114   Module
  115. 115   00007ff914237968    Dynamic Module
  116. 116
  117. 117 Assembly:           000001fecb90b480 (Dynamic) []
  118. 118 ClassLoader:        000001FECA8B0FA0
  119. 119   Module
  120. 120   00007ff914238430    Dynamic Module
  121. 121
  122. 122 Assembly:           000001fecb90b8a0 (Dynamic) []
  123. 123 ClassLoader:        000001FECA8B4C20
  124. 124   Module
  125. 125   00007ff914238ef8    Dynamic Module
  126. 126
  127. 127 Assembly:           000001fecb90c860 (Dynamic) []
  128. 128 ClassLoader:        000001FECA8B4960
  129. 129   Module
  130. 130   00007ff9142399c0    Dynamic Module
  131. 131
  132. 132 Assembly:           000001fecb90c980 (Dynamic) []
  133. 133 ClassLoader:        000001FECA8B4280
  134. 134   Module
  135. 135   00007ff91423a488    Dynamic Module
  136. 136
  137. 137 Assembly:           000001fecb90c920 (Dynamic) []
  138. 138 ClassLoader:        000001FECA8B4070
  139. 139   Module
  140. 140   00007ff91423af50    Dynamic Module
复制代码
                  我们看到这个模块的特性【Attributes】的值是 Reflection IsDynamic IsInMemoryReflection 表示是反射的,IsDynamic 表示是动态的(不是我们手动创建的),IsInMemory 表示是在内存中创建生成的,这三个词就是说,这个模块式是通过反射技术在内存中动态创建的。
                  有一点,我们可以知道,就是这些程序集是我们的程序动态创建的,那我们去托管线程调用栈看看不就清楚了。
                  首先,我们要执行【~0s】命令切换到托管线程上下文中,然后,执行【!clrstack】命令。
  1. 1 0:008> !DumpModule 00007ff91423af50
  2. 2 Name: Unknown Module
  3. 3 <strong>Attributes:              Reflection IsDynamic IsInMemory
  4. </strong> 4 TransientFlags:          00200811
  5. 5 Assembly:                000001fecb90c920
  6. 6 BaseAddress:             0000000000000000
  7. 7 PEAssembly:              000001FECB9B0510
  8. 8 ModuleId:                00007FF91423B350
  9. 9 ModuleIndex:             0000000000001012
  10. 10 LoaderHeap:              00007FF96F6D4588
  11. 11 TypeDefToMethodTableMap: 00007FF91427E100
  12. 12 TypeRefToMethodTableMap: 00007FF91427E128
  13. 13 MethodDefToDescMap:      00007FF91427E1A0
  14. 14 FieldDefToDescMap:       00007FF91427E1F0
  15. 15 MemberRefToDescMap:      00007FF91427E150
  16. 16 FileReferencesMap:       0000000000000000
  17. 17 AssemblyReferencesMap:   00007FF91427E290
复制代码
                  我们看到了 System.Xml.Serialization.XmlSerializer..ctor 类型的实例化,在该类型内部又调用了 System.Xml.Serialization.XmlSerializer.GenerateTempAssembly 创建临时程序集,看来问题我们找到了,那就容易了。

                  我们再说一种情况,如果程序直接运行到崩溃,并报告一个 OutOfMemoryException 的异常怎么办?当然,这样又分两种情况,如果程序是自己的,可以通过调试器附近进程进行调试,如果程序是别人的,不能直接调试程序,就只能通过抓 Dump 来实现调试了。抓 Dump 有两种方式,一种是使用【任务管理器】,一种是使用【ProcessExplorer】工具。
                  这个调试就不演示了,大概过程就是,我们【g】继续,直到我们的程序崩溃,抛出内存溢出的异常为止,我们可以使用【kb】命令找到异常地址,再使用【!PrintException】打印异常信息,也可以找到具体的问题。


四、总结
    这篇文章的终于写完了,这篇文章的内容相对来说,不是很多。写完一篇,就说明进步了一点点。Net 高级调试这条路,也刚刚起步,还有很多要学的地方。皇天不负有心人,努力,不辜负自己,我相信付出就有回报,再者说,学习的过程,有时候,虽然很痛苦,但是,学有所成,学有所懂,这个开心的感觉还是不可言喻的。不忘初心,继续努力。做自己喜欢做的,开心就好。

来源:https://www.cnblogs.com/PatrickLiu/p/18120588
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具