<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      cpu 和垃圾回收的關(guān)系

      前言

      前文中介紹了,cpu 使用率和三個(gè)方面有關(guān),一個(gè)是中斷、一個(gè)是用戶(hù)時(shí)間、一個(gè)是系統(tǒng)時(shí)間。

      那么當(dāng)我們排查問(wèn)題時(shí)候,查到是用戶(hù)時(shí)間占用比較多的話,那么該如何排查呢?

      正文

      首先我們想到的是,cpu高嘛,查看火焰圖對(duì)吧。 火焰圖可以看到哪個(gè)函數(shù)消耗cpu比較多?

      似乎這個(gè)問(wèn)題好像馬上能查看到,如果火焰圖調(diào)入gc函數(shù)消耗的cpu比較多的話,那么就直接定位了。

      然而事情好像沒(méi)有這么簡(jiǎn)單。

      這個(gè)我們來(lái)看一下火焰圖原理:

      火焰圖是一種性能分析工具,它通過(guò)采樣CPU調(diào)用棧來(lái)生成可視化的性能分析圖表。火焰圖能夠顯示:

      1.CPU時(shí)間消耗最多的函數(shù)調(diào)用路徑
      2. 調(diào)用棧的深度和寬度
      3. 熱點(diǎn)代碼的位置

      GC在火焰圖中的表現(xiàn)

      1. GC線程活動(dòng):如果GC線程占用大量CPU時(shí)間,會(huì)在火焰圖中顯示為GC相關(guān)的調(diào)用棧
      2. GC暫停時(shí)間:雖然火焰圖主要顯示CPU時(shí)間,但GC暫停期間的CPU使用也會(huì)被記錄
      3. 內(nèi)存分配熱點(diǎn):頻繁的內(nèi)存分配會(huì)導(dǎo)致GC壓力,這些分配點(diǎn)會(huì)在火焰圖中顯示

      可能觀察不到的情況:

      1. 后臺(tái)GC:.NET的Server GC模式使用后臺(tái)線程進(jìn)行垃圾回收,這些線程的活動(dòng)可能不會(huì)在火焰圖中明顯顯示
      2. GC暫停:GC暫停期間應(yīng)用程序線程被掛起,火焰圖可能顯示為"空閑"時(shí)間

      也就是說(shuō)火焰圖可能能看出一些gc問(wèn)題,但是有些可能不明顯。

      那么從簡(jiǎn)單的說(shuō),內(nèi)存分配熱點(diǎn),也就是說(shuō)內(nèi)存頻繁的分配,那么可以查看出。

      這個(gè)其實(shí)占用cpu的話,經(jīng)過(guò)測(cè)試,這個(gè)其實(shí)一般來(lái)說(shuō)占用cpu不會(huì)太多,很難看出來(lái)。

      比如說(shuō):

      using System;
      using System.Collections.Generic;
      using System.Threading;
      using System.Threading.Tasks;
      using System.Text;
      
      namespace RealAllocationHotspot
      {
          class Program
          {
              static void Main(string[] args)
              {
                  Console.WriteLine("Real Memory Allocation Hotspot Demo");
                  Console.WriteLine("This will show actual allocation hotspots in flame graphs");
                  
                  var cts = new CancellationTokenSource();
                  var tasks = new List<Task>();
      
                  // 任務(wù)1:CPU密集型的分配熱點(diǎn)
                  tasks.Add(Task.Run(() => CpuIntensiveAllocation(cts.Token)));
      
                  // 任務(wù)2:字符串操作熱點(diǎn)
                  tasks.Add(Task.Run(() => StringAllocationHotspot(cts.Token)));
      
                  // 任務(wù)3:集合操作熱點(diǎn)
                  tasks.Add(Task.Run(() => CollectionAllocationHotspot(cts.Token)));
      
                  // 任務(wù)4:復(fù)雜對(duì)象分配熱點(diǎn)
                  tasks.Add(Task.Run(() => ComplexObjectAllocation(cts.Token)));
      
                  Console.WriteLine("Press any key to stop...");
                  Console.ReadKey();
                  cts.Cancel();
      
                  Task.WaitAll(tasks.ToArray());
              }
      
              // CPU密集型的分配熱點(diǎn) - 會(huì)在火焰圖中顯示
              static void CpuIntensiveAllocation(CancellationToken token)
              {
                  while (!token.IsCancellationRequested)
                  {
                      // 這些操作會(huì)消耗大量CPU時(shí)間
                      for (int i = 0; i < 10000; i++)
                      {
                          // 熱點(diǎn)1:大量字符串操作
                          var result = "";
                          for (int j = 0; j < 100; j++)
                          {
                              result += $"String_{i}_{j}_";  // 字符串連接
                              result += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                          }
      
                          // 熱點(diǎn)2:字符串格式化
                          var formatted = string.Format("Complex string: {0}, {1}, {2}, {3}, {4}", 
                              Guid.NewGuid(), DateTime.Now, Environment.TickCount, 
                              i);
      
                          // 熱點(diǎn)3:數(shù)組操作
                          var array = new byte[1000];
                          for (int k = 0; k < array.Length; k++)
                          {
                              array[k] = (byte)(i + k);
                          }
                      }
                  }
              }
      
              // 字符串分配熱點(diǎn) - 會(huì)顯示為CPU熱點(diǎn)
              static void StringAllocationHotspot(CancellationToken token)
              {
                  while (!token.IsCancellationRequested)
                  {
                      // 這些操作會(huì)消耗CPU時(shí)間進(jìn)行字符串處理
                      for (int i = 0; i < 5000; i++)
                      {
                          // 熱點(diǎn):字符串連接操作
                          var sb = new StringBuilder();
                          for (int j = 0; j < 50; j++)
                          {
                              sb.Append($"String_{i}_{j}_");
                              sb.Append(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                              sb.Append("_");
                          }
                          var result = sb.ToString();
      
                          // 熱點(diǎn):字符串分割和重組
                          var parts = result.Split('_');
                          var reconstructed = string.Join("|", parts);
                      }
                  }
              }
      
              // 集合分配熱點(diǎn) - 會(huì)顯示為CPU熱點(diǎn)
              static void CollectionAllocationHotspot(CancellationToken token)
              {
                  while (!token.IsCancellationRequested)
                  {
                      // 這些操作會(huì)消耗CPU時(shí)間進(jìn)行集合操作
                      for (int i = 0; i < 1000; i++)
                      {
                          // 熱點(diǎn):列表操作
                          var list = new List<string>();
                          for (int j = 0; j < 100; j++)
                          {
                              list.Add($"Item_{i}_{j}");
                          }
      
                          // 熱點(diǎn):字典操作
                          var dict = new Dictionary<string, object>();
                          for (int j = 0; j < 50; j++)
                          {
                              dict[$"Key_{i}_{j}"] = new byte[100];
                          }
      
                          // 熱點(diǎn):集合操作
                          var set = new HashSet<string>();
                          for (int j = 0; j < 100; j++)
                          {
                              set.Add($"SetItem_{i}_{j}");
                          }
                      }
                  }
              }
      
              // 復(fù)雜對(duì)象分配熱點(diǎn) - 會(huì)顯示為CPU熱點(diǎn)
              static void ComplexObjectAllocation(CancellationToken token)
              {
                  while (!token.IsCancellationRequested)
                  {
                      // 這些操作會(huì)消耗CPU時(shí)間進(jìn)行對(duì)象創(chuàng)建和初始化
                      for (int i = 0; i < 1000; i++)
                      {
                          // 熱點(diǎn):復(fù)雜對(duì)象創(chuàng)建
                          var complexObject = new ComplexObject
                          {
                              Id = i,
                              Name = $"ComplexObject_{i}",
                              Data = new byte[500],
                              Tags = new List<string> { "tag1", "tag2", "tag3" },
                              Properties = new Dictionary<string, object>
                              {
                                  ["prop1"] = Guid.NewGuid(),
                                  ["prop2"] = DateTime.Now,
                                  ["prop3"] = Environment.TickCount
                              }
                          };
      
                          // 熱點(diǎn):對(duì)象序列化/反序列化模擬
                          var serialized = complexObject.ToString();
                          var deserialized = ComplexObject.FromString(serialized);
                      }
                  }
              }
          }
      
          // 復(fù)雜對(duì)象 - 用于演示分配熱點(diǎn)
          class ComplexObject
          {
              public int Id { get; set; }
              public string Name { get; set; }
              public byte[] Data { get; set; }
              public List<string> Tags { get; set; }
              public Dictionary<string, object> Properties { get; set; }
      
              public override string ToString()
              {
                  return $"ComplexObject{{Id={Id}, Name={Name}, DataLength={Data?.Length ?? 0}}}";
              }
      
              public static ComplexObject FromString(string str)
              {
                  // 模擬反序列化
                  return new ComplexObject { Id = 0, Name = str };
              }
          }
      }
      

      那么來(lái)看一下cpu火焰圖:

      image

      可以看到一個(gè)datetime的now,后面都是大量的擴(kuò)容創(chuàng)建對(duì)象啥的。

      GC暫停時(shí)間:雖然火焰圖主要顯示CPU時(shí)間,但GC暫停期間的CPU使用也會(huì)被記錄。

      這個(gè)怎么說(shuō)呢?

      // .NET中有兩種GC模式:
      // 1. 工作站GC (Workstation GC) - 前臺(tái)GC,會(huì)暫停所有線程
      // 2. 服務(wù)器GC (Server GC) - 后臺(tái)GC,使用專(zhuān)用線程

      然后這兩種工作狀態(tài)呢?

      // GC暫停期間,應(yīng)用程序線程的狀態(tài):
      // 1. 前臺(tái)GC:所有線程被掛起
      // 2. 后臺(tái)GC:應(yīng)用程序線程繼續(xù)運(yùn)行,GC線程在后臺(tái)工作
      

      這里說(shuō)的是gc暫停時(shí)間呢?說(shuō)的是前臺(tái)gc,所有的線程被掛起的情況。

      前臺(tái)gc暫停:

      明顯可見(jiàn):前臺(tái)GC會(huì)暫停所有用戶(hù)線程,在火焰圖中表現(xiàn)為明顯的"熱點(diǎn)"

      具體表現(xiàn):

      GC.Collect() 調(diào)用會(huì)顯示為CPU熱點(diǎn)
      GC.WaitForPendingFinalizers() 會(huì)顯示為等待時(shí)間
      用戶(hù)線程在GC期間會(huì)顯示為 WaitHandle.WaitOne 或 Thread.Sleep

      GC.Collect() 和 GC.WaitForPendingFinalizers() 是gc回收的函數(shù)。

      using System;
      using System.Collections.Generic;
      using System.Diagnostics;
      using System.Threading;
      using System.Threading.Tasks;
      
      namespace GCPauseFlameDemo
      {
          /// <summary>
          /// 演示GC暫停在火焰圖中的不同表現(xiàn)
          /// </summary>
          public class GCFlameGraphDemo
          {
              public static void RunDemo()
              {
                  Console.WriteLine("=== GC暫停在火焰圖中的表現(xiàn)演示 ===");
                  Console.WriteLine();
                  Console.WriteLine("請(qǐng)選擇測(cè)試模式:");
                  Console.WriteLine("1. 前臺(tái)GC演示 - 會(huì)明顯顯示在火焰圖中");
                  Console.WriteLine("2. 后臺(tái)GC演示 - 可能不明顯");
                  Console.WriteLine("3. 業(yè)務(wù)邏輯演示 - 在GC暫停期間會(huì)受到影響");
                  Console.WriteLine("4. 密集GC演示 - 專(zhuān)門(mén)設(shè)計(jì)用于在火焰圖中產(chǎn)生明顯熱點(diǎn)");
                  Console.WriteLine("5. 超激進(jìn)GC演示 - 嘗試在用戶(hù)線程上產(chǎn)生明顯的GC相關(guān)CPU使用");
                  Console.WriteLine("6. GC活動(dòng)診斷 - 監(jiān)控GC相關(guān)指標(biāo)并解釋火焰圖表現(xiàn)");
                  Console.WriteLine("7. 混合模式 - 所有任務(wù)同時(shí)運(yùn)行(用于對(duì)比)");
                  Console.WriteLine("8. 分階段測(cè)試 - 依次測(cè)試每種模式");
                  Console.WriteLine();
                  Console.Write("請(qǐng)輸入選擇 (1-8): ");
                  
                  var choice = Console.ReadLine();
                  
                  switch (choice)
                  {
                      case "1":
                          RunForegroundGCDemo();
                          break;
                      case "2":
                          RunBackgroundGCDemo();
                          break;
                      case "3":
                          RunBusinessLogicDemo();
                          break;
                      case "4":
                          RunIntensiveGCDemo();
                          break;
                      case "5":
                          RunUltraIntensiveGCDemo();
                          break;
                      case "6":
                          RunDiagnoseGCActivity();
                          break;
                      case "7":
                          RunMixedDemo();
                          break;
                      case "8":
                          RunStagedDemo();
                          break;
                      default:
                          Console.WriteLine("無(wú)效選擇,運(yùn)行混合模式演示...");
                          RunMixedDemo();
                          break;
                  }
              }
      
              /// <summary>
              /// 演示前臺(tái)GC - 在火焰圖中會(huì)顯示為明顯的熱點(diǎn)
              /// </summary>
              static void DemonstrateForegroundGC(CancellationToken token)
              {
                  Console.WriteLine("前臺(tái)GC演示開(kāi)始 - 這些操作會(huì)在火焰圖中顯示為熱點(diǎn)");
                  
                  while (!token.IsCancellationRequested)
                  {
                      // 大量分配內(nèi)存,確保觸發(fā)GC
                      var objects = new List<object>();
                      for (int i = 0; i < 200000; i++)  // 增加分配量
                      {
                          objects.Add(new byte[2000]); // 分配400MB
                      }
      
                      // 強(qiáng)制觸發(fā)前臺(tái)GC - 這會(huì)在火焰圖中顯示為CPU熱點(diǎn)
                      var sw = Stopwatch.StartNew();
                      
                      // 多次調(diào)用GC,確保在火焰圖中可見(jiàn)
                      for (int i = 0; i < 5; i++)  // 連續(xù)調(diào)用5次
                      {
                          GC.Collect(0, GCCollectionMode.Forced);
                          GC.WaitForPendingFinalizers();
                          
                          // 短暫休眠,讓采樣器有機(jī)會(huì)捕獲
                          Thread.Sleep(10);
                      }
                      
                      sw.Stop();
                      
                      Console.WriteLine($"[前臺(tái)GC] 強(qiáng)制GC耗時(shí): {sw.ElapsedMilliseconds}ms");
                      
                      // 減少休眠時(shí)間,增加GC調(diào)用頻率
                      Thread.Sleep(200);
                  }
              }
      
              /// <summary>
              /// 演示后臺(tái)GC - 在火焰圖中可能不明顯
              /// </summary>
              static void DemonstrateBackgroundGC(CancellationToken token)
              {
                  Console.WriteLine("后臺(tái)GC演示開(kāi)始 - 這些操作在火焰圖中可能不明顯");
                  
                  while (!token.IsCancellationRequested)
                  {
                      // 大量分配,讓后臺(tái)GC自然觸發(fā)
                      var objects = new List<object>();
                      for (int i = 0; i < 50000; i++)
                      {
                          objects.Add(new byte[2000]); // 分配100MB
                      }
      
                      // 不強(qiáng)制GC,讓后臺(tái)GC線程自然工作
                      // 后臺(tái)GC線程的工作可能不會(huì)在火焰圖中明顯顯示
                      
                      Thread.Sleep(300);
                  }
              }
      
              /// <summary>
              /// 演示業(yè)務(wù)邏輯在GC暫停期間的表現(xiàn)
              /// </summary>
              static void DemonstrateBusinessLogic(CancellationToken token)
              {
                  Console.WriteLine("業(yè)務(wù)邏輯演示開(kāi)始 - 在GC暫停期間會(huì)受到影響");
                  
                  while (!token.IsCancellationRequested)
                  {
                      // 模擬正常的業(yè)務(wù)邏輯
                      var sw = Stopwatch.StartNew();
                      
                      // 密集計(jì)算
                      for (int i = 0; i < 10000; i++)
                      {
                          var result = Math.Sqrt(i) * Math.PI;
                      }
                      
                      sw.Stop();
                      
                      // 如果業(yè)務(wù)邏輯在GC暫停期間執(zhí)行,可能會(huì)顯示為:
                      // - Thread.Sleep (等待GC完成)
                      // - WaitHandle.WaitOne (等待GC完成)
                      // - 執(zhí)行時(shí)間異常長(zhǎng)
                      
                      Console.WriteLine($"[業(yè)務(wù)邏輯] 計(jì)算耗時(shí): {sw.ElapsedMilliseconds}ms");
                      
                      Thread.Sleep(100);
                  }
              }
      
              /// <summary>
              /// 專(zhuān)門(mén)用于在火焰圖中產(chǎn)生明顯GC熱點(diǎn)的方法
              /// </summary>
              static void DemonstrateIntensiveGC(CancellationToken token)
              {
                  Console.WriteLine("密集GC演示開(kāi)始 - 專(zhuān)門(mén)設(shè)計(jì)用于在火焰圖中產(chǎn)生明顯熱點(diǎn)");
                  Console.WriteLine("注意:GC工作主要在專(zhuān)用線程上,可能不會(huì)在用戶(hù)線程的火焰圖中顯示");
                  
                  while (!token.IsCancellationRequested)
                  {
                      // 創(chuàng)建大量對(duì)象,確保觸發(fā)GC
                      var objects = new List<object>();
                      for (int i = 0; i < 500000; i++)  // 大量分配
                      {
                          objects.Add(new byte[1000]); // 分配500MB
                      }
      
                      // 密集調(diào)用GC,確保在火焰圖中可見(jiàn)
                      var sw = Stopwatch.StartNew();
                      
                      // 連續(xù)多次GC,產(chǎn)生明顯的CPU熱點(diǎn)
                      for (int j = 0; j < 10; j++)  // 10次循環(huán)
                      {
                          // 強(qiáng)制Gen0 GC
                          GC.Collect(0, GCCollectionMode.Forced);
                          GC.WaitForPendingFinalizers();
                          
                          // 強(qiáng)制Gen1 GC
                          GC.Collect(1, GCCollectionMode.Forced);
                          GC.WaitForPendingFinalizers();
                          
                          // 強(qiáng)制Gen2 GC(最耗時(shí))
                          GC.Collect(2, GCCollectionMode.Forced);
                          GC.WaitForPendingFinalizers();
                          
                          // 短暫休眠,讓采樣器捕獲
                          Thread.Sleep(5);
                      }
                      
                      sw.Stop();
                      
                      Console.WriteLine($"[密集GC] 強(qiáng)制GC耗時(shí): {sw.ElapsedMilliseconds}ms");
                      
                      // 短暫休眠后繼續(xù)
                      Thread.Sleep(100);
                  }
              }
      
              /// <summary>
              /// 超激進(jìn)GC測(cè)試 - 嘗試在用戶(hù)線程上產(chǎn)生明顯的GC相關(guān)CPU使用
              /// </summary>
              static void DemonstrateUltraIntensiveGC(CancellationToken token)
              {
                  Console.WriteLine("超激進(jìn)GC演示開(kāi)始 - 嘗試在用戶(hù)線程上產(chǎn)生明顯的GC相關(guān)CPU使用");
                  Console.WriteLine("這個(gè)測(cè)試會(huì)嘗試在用戶(hù)線程上執(zhí)行GC相關(guān)工作");
                  
                  while (!token.IsCancellationRequested)
                  {
                      // 創(chuàng)建大量對(duì)象
                      var objects = new List<object>();
                      for (int i = 0; i < 1000000; i++)  // 1M個(gè)對(duì)象
                      {
                          objects.Add(new byte[1000]); // 分配1GB
                      }
      
                      var sw = Stopwatch.StartNew();
                      
                      // 在用戶(hù)線程上執(zhí)行密集的GC相關(guān)操作
                      for (int j = 0; j < 20; j++)  // 20次循環(huán)
                      {
                          // 連續(xù)調(diào)用GC,嘗試在用戶(hù)線程上產(chǎn)生CPU熱點(diǎn)
                          for (int k = 0; k < 5; k++)
                          {
                              GC.Collect(0, GCCollectionMode.Forced);
                              GC.WaitForPendingFinalizers();
                              
                              // 在用戶(hù)線程上執(zhí)行一些計(jì)算,確保CPU使用
                              for (int l = 0; l < 10000; l++)
                              {
                                  var result = Math.Sqrt(l) * Math.PI;
                              }
                          }
                          
                          // 強(qiáng)制Gen1和Gen2 GC
                          GC.Collect(1, GCCollectionMode.Forced);
                          GC.WaitForPendingFinalizers();
                          
                          GC.Collect(2, GCCollectionMode.Forced);
                          GC.WaitForPendingFinalizers();
                          
                          // 在用戶(hù)線程上執(zhí)行更多計(jì)算
                          for (int l = 0; l < 5000; l++)
                          {
                              var result = Math.Sin(l) * Math.Cos(l);
                          }
                      }
                      
                      sw.Stop();
                      
                      Console.WriteLine($"[超激進(jìn)GC] 強(qiáng)制GC耗時(shí): {sw.ElapsedMilliseconds}ms");
                      Console.WriteLine($"當(dāng)前內(nèi)存使用: {GC.GetTotalMemory(false) / 1024 / 1024} MB");
                      
                      Thread.Sleep(50);
                  }
              }
      
              /// <summary>
              /// 診斷GC活動(dòng)的方法
              /// </summary>
              static void DiagnoseGCActivity(CancellationToken token)
              {
                  Console.WriteLine("GC活動(dòng)診斷開(kāi)始 - 監(jiān)控GC相關(guān)指標(biāo)");
                  
                  var lastGen0 = GC.CollectionCount(0);
                  var lastGen1 = GC.CollectionCount(1);
                  var lastGen2 = GC.CollectionCount(2);
                  var lastMemory = GC.GetTotalMemory(false);
      
                  while (!token.IsCancellationRequested)
                  {
                      var currentGen0 = GC.CollectionCount(0);
                      var currentGen1 = GC.CollectionCount(1);
                      var currentGen2 = GC.CollectionCount(2);
                      var currentMemory = GC.GetTotalMemory(false);
      
                      if (currentGen0 > lastGen0 || currentGen1 > lastGen1 || currentGen2 > lastGen2)
                      {
                          Console.WriteLine($"\n=== GC事件檢測(cè)到 [{DateTime.Now:HH:mm:ss.fff}] ===");
                          Console.WriteLine($"Gen0: {currentGen0 - lastGen0} 次");
                          Console.WriteLine($"Gen1: {currentGen1 - lastGen1} 次");
                          Console.WriteLine($"Gen2: {currentGen2 - lastGen2} 次");
                          Console.WriteLine($"內(nèi)存變化: {(currentMemory - lastMemory) / 1024 / 1024} MB");
                          Console.WriteLine($"總內(nèi)存: {currentMemory / 1024 / 1024} MB");
                          
                          // 解釋為什么GC可能不在火焰圖中顯示
                          Console.WriteLine("?? 火焰圖分析:");
                          Console.WriteLine("   - GC.Collect() 調(diào)用會(huì)在火焰圖中顯示");
                          Console.WriteLine("   - GC.WaitForPendingFinalizers() 會(huì)顯示為等待");
                          Console.WriteLine("   - 但GC的實(shí)際工作在專(zhuān)用線程上,可能不顯示");
                          Console.WriteLine("   - 用戶(hù)線程的等待會(huì)顯示為 Thread.Sleep 或 WaitHandle.WaitOne");
                      }
      
                      lastGen0 = currentGen0;
                      lastGen1 = currentGen1;
                      lastGen2 = currentGen2;
                      lastMemory = currentMemory;
      
                      Thread.Sleep(500);
                  }
              }
      
              /// <summary>
              /// 監(jiān)控GC活動(dòng)并解釋火焰圖表現(xiàn)
              /// </summary>
              static void MonitorGCWithFlameGraph(CancellationToken token)
              {
                  var lastGen0 = GC.CollectionCount(0);
                  var lastGen1 = GC.CollectionCount(1);
                  var lastGen2 = GC.CollectionCount(2);
      
                  Console.WriteLine("GC監(jiān)控開(kāi)始 - 觀察火焰圖中的表現(xiàn)");
      
                  while (!token.IsCancellationRequested)
                  {
                      var currentGen0 = GC.CollectionCount(0);
                      var currentGen1 = GC.CollectionCount(1);
                      var currentGen2 = GC.CollectionCount(2);
      
                      if (currentGen0 > lastGen0 || currentGen1 > lastGen1 || currentGen2 > lastGen2)
                      {
                          Console.WriteLine($"\n=== GC事件檢測(cè)到 [{DateTime.Now:HH:mm:ss.fff}] ===");
                          Console.WriteLine($"Gen0: {currentGen0 - lastGen0} 次");
                          Console.WriteLine($"Gen1: {currentGen1 - lastGen1} 次");
                          Console.WriteLine($"Gen2: {currentGen2 - lastGen2} 次");
                          Console.WriteLine($"總內(nèi)存: {GC.GetTotalMemory(false) / 1024 / 1024} MB");
                          
                          // 解釋火焰圖中的表現(xiàn)
                          if (currentGen2 > lastGen2)
                          {
                              Console.WriteLine("?? 火焰圖表現(xiàn): Gen2 GC會(huì)在火焰圖中顯示為明顯的CPU熱點(diǎn)");
                              Console.WriteLine("   用戶(hù)線程會(huì)顯示為 WaitHandle.WaitOne 或 Thread.Sleep");
                          }
                          else if (currentGen1 > lastGen1)
                          {
                              Console.WriteLine("?? 火焰圖表現(xiàn): Gen1 GC可能顯示為中等程度的CPU使用");
                          }
                          else
                          {
                              Console.WriteLine("?? 火焰圖表現(xiàn): Gen0 GC可能顯示為輕微的CPU使用");
                          }
                      }
      
                      lastGen0 = currentGen0;
                      lastGen1 = currentGen1;
                      lastGen2 = currentGen2;
      
                      Thread.Sleep(1000);
                  }
              }
      
              /// <summary>
              /// 單獨(dú)測(cè)試前臺(tái)GC
              /// </summary>
              static void RunForegroundGCDemo()
              {
                  Console.WriteLine("\n=== 前臺(tái)GC演示 ===");
                  Console.WriteLine("前臺(tái)GC會(huì)在火焰圖中顯示為明顯的CPU熱點(diǎn)");
                  Console.WriteLine("按任意鍵開(kāi)始,再次按任意鍵停止...");
                  Console.ReadKey();
                  
                  var cts = new CancellationTokenSource();
                  var task = Task.Run(() => DemonstrateForegroundGC(cts.Token));
                  
                  Console.ReadKey();
                  cts.Cancel();
                  task.Wait();
              }
      
              /// <summary>
              /// 單獨(dú)測(cè)試后臺(tái)GC
              /// </summary>
              static void RunBackgroundGCDemo()
              {
                  Console.WriteLine("\n=== 后臺(tái)GC演示 ===");
                  Console.WriteLine("后臺(tái)GC在火焰圖中可能不明顯");
                  Console.WriteLine("按任意鍵開(kāi)始,再次按任意鍵停止...");
                  Console.ReadKey();
                  
                  var cts = new CancellationTokenSource();
                  var task = Task.Run(() => DemonstrateBackgroundGC(cts.Token));
                  
                  Console.ReadKey();
                  cts.Cancel();
                  task.Wait();
              }
      
              /// <summary>
              /// 單獨(dú)測(cè)試業(yè)務(wù)邏輯
              /// </summary>
              static void RunBusinessLogicDemo()
              {
                  Console.WriteLine("\n=== 業(yè)務(wù)邏輯演示 ===");
                  Console.WriteLine("業(yè)務(wù)邏輯在GC暫停期間會(huì)受到影響");
                  Console.WriteLine("按任意鍵開(kāi)始,再次按任意鍵停止...");
                  Console.ReadKey();
                  
                  var cts = new CancellationTokenSource();
                  var task = Task.Run(() => DemonstrateBusinessLogic(cts.Token));
                  
                  Console.ReadKey();
                  cts.Cancel();
                  task.Wait();
              }
      
              /// <summary>
              /// 混合模式 - 所有任務(wù)同時(shí)運(yùn)行
              /// </summary>
              static void RunMixedDemo()
              {
                  Console.WriteLine("\n=== 混合模式演示 ===");
                  Console.WriteLine("所有任務(wù)同時(shí)運(yùn)行,用于對(duì)比不同GC類(lèi)型的影響");
                  Console.WriteLine("按任意鍵開(kāi)始,再次按任意鍵停止...");
                  Console.ReadKey();
                  
                  var cts = new CancellationTokenSource();
                  var tasks = new List<Task>();
      
                  tasks.Add(Task.Run(() => DemonstrateForegroundGC(cts.Token)));
                  tasks.Add(Task.Run(() => DemonstrateBackgroundGC(cts.Token)));
                  tasks.Add(Task.Run(() => DemonstrateBusinessLogic(cts.Token)));
                  tasks.Add(Task.Run(() => MonitorGCWithFlameGraph(cts.Token)));
      
                  Console.ReadKey();
                  cts.Cancel();
                  Task.WaitAll(tasks.ToArray());
              }
      
              /// <summary>
              /// 分階段測(cè)試 - 依次測(cè)試每種模式
              /// </summary>
              static void RunStagedDemo()
              {
                  Console.WriteLine("\n=== 分階段測(cè)試 ===");
                  Console.WriteLine("將依次測(cè)試每種GC類(lèi)型,每次測(cè)試30秒");
                  
                  // 階段1:前臺(tái)GC
                  Console.WriteLine("\n--- 階段1:前臺(tái)GC測(cè)試 (30秒) ---");
                  Console.WriteLine("前臺(tái)GC會(huì)在火焰圖中顯示為明顯的CPU熱點(diǎn)");
                  Console.WriteLine("按任意鍵開(kāi)始...");
                  Console.ReadKey();
                  
                  var cts1 = new CancellationTokenSource();
                  var task1 = Task.Run(() => DemonstrateForegroundGC(cts1.Token));
                  Thread.Sleep(30000); // 30秒
                  cts1.Cancel();
                  task1.Wait();
                  
                  // 階段2:后臺(tái)GC
                  Console.WriteLine("\n--- 階段2:后臺(tái)GC測(cè)試 (30秒) ---");
                  Console.WriteLine("后臺(tái)GC在火焰圖中可能不明顯");
                  Console.WriteLine("按任意鍵開(kāi)始...");
                  Console.ReadKey();
                  
                  var cts2 = new CancellationTokenSource();
                  var task2 = Task.Run(() => DemonstrateBackgroundGC(cts2.Token));
                  Thread.Sleep(30000); // 30秒
                  cts2.Cancel();
                  task2.Wait();
                  
                  // 階段3:業(yè)務(wù)邏輯
                  Console.WriteLine("\n--- 階段3:業(yè)務(wù)邏輯測(cè)試 (30秒) ---");
                  Console.WriteLine("業(yè)務(wù)邏輯在GC暫停期間會(huì)受到影響");
                  Console.WriteLine("按任意鍵開(kāi)始...");
                  Console.ReadKey();
                  
                  var cts3 = new CancellationTokenSource();
                  var task3 = Task.Run(() => DemonstrateBusinessLogic(cts3.Token));
                  Thread.Sleep(30000); // 30秒
                  cts3.Cancel();
                  task3.Wait();
                  
                  Console.WriteLine("\n=== 分階段測(cè)試完成 ===");
                  Console.WriteLine("現(xiàn)在可以分析每個(gè)階段的火焰圖表現(xiàn)");
              }
      
              /// <summary>
              /// 單獨(dú)測(cè)試密集GC
              /// </summary>
              static void RunIntensiveGCDemo()
              {
                  Console.WriteLine("\n=== 密集GC演示 ===");
                  Console.WriteLine("專(zhuān)門(mén)設(shè)計(jì)用于在火焰圖中產(chǎn)生明顯的GC熱點(diǎn)");
                  Console.WriteLine("這個(gè)演示會(huì)頻繁調(diào)用GC,確保在火焰圖中可見(jiàn)");
                  Console.WriteLine("按任意鍵開(kāi)始,再次按任意鍵停止...");
                  Console.ReadKey();
                  
                  var cts = new CancellationTokenSource();
                  var task = Task.Run(() => DemonstrateIntensiveGC(cts.Token));
                  
                  Console.ReadKey();
                  cts.Cancel();
                  task.Wait();
              }
      
              /// <summary>
              /// 單獨(dú)測(cè)試超激進(jìn)GC
              /// </summary>
              static void RunUltraIntensiveGCDemo()
              {
                  Console.WriteLine("\n=== 超激進(jìn)GC演示 ===");
                  Console.WriteLine("嘗試在用戶(hù)線程上產(chǎn)生明顯的GC相關(guān)CPU使用");
                  Console.WriteLine("這個(gè)測(cè)試會(huì)在用戶(hù)線程上執(zhí)行密集的GC相關(guān)操作");
                  Console.WriteLine("按任意鍵開(kāi)始,再次按任意鍵停止...");
                  Console.ReadKey();
                  
                  var cts = new CancellationTokenSource();
                  var task = Task.Run(() => DemonstrateUltraIntensiveGC(cts.Token));
                  
                  Console.ReadKey();
                  cts.Cancel();
                  task.Wait();
              }
      
              /// <summary>
              /// 運(yùn)行GC活動(dòng)診斷
              /// </summary>
              static void RunDiagnoseGCActivity()
              {
                  Console.WriteLine("\n=== GC活動(dòng)診斷 ===");
                  Console.WriteLine("監(jiān)控GC相關(guān)指標(biāo)并解釋火焰圖表現(xiàn)");
                  Console.WriteLine("這個(gè)測(cè)試會(huì)解釋為什么GC可能不在火焰圖中顯示");
                  Console.WriteLine("按任意鍵開(kāi)始,再次按任意鍵停止...");
                  Console.ReadKey();
                  
                  var cts = new CancellationTokenSource();
                  var task = Task.Run(() => DiagnoseGCActivity(cts.Token));
                  
                  Console.ReadKey();
                  cts.Cancel();
                  task.Wait();
              }
          }
      } 
      

      運(yùn)行5的時(shí)候呢,大量gc的時(shí)候出現(xiàn)了gc函數(shù)的調(diào)用,但是呢,火焰圖看不到gc線程具體執(zhí)行的信息。

      dotnet-trace collect -p 53632  --format speedscope --providers Microsoft-DotNETCore-SampleProfiler --duration 00:00:30 --symbols ./bin/Debug/net8.0/
      

      根本原因分析

      1. SampleProfiler 的工作原理

      CPU 采樣機(jī)制

      SampleProfiler 采樣原理:
      ├── 定期中斷用戶(hù)線程
      ├── 收集當(dāng)前調(diào)用棧
      ├── 統(tǒng)計(jì) CPU 使用時(shí)間
      └── 生成火焰圖數(shù)據(jù)
      

      對(duì) GC 的限制

      GC 工作的特點(diǎn):
      ├── GC 工作在專(zhuān)用線程上
      ├── 用戶(hù)線程在 GC 期間被暫停
      ├── SampleProfiler 主要采樣用戶(hù)線程
      └── GC 線程可能不被采樣
      
      ### 2. **為什么 SampleProfiler 抓取不到 GC**
      
      #### 原因1:GC 線程隔離
      ```csharp
      // GC 工作流程
      用戶(hù)線程: GC.Collect() → 等待 GC 完成 → 繼續(xù)執(zhí)行
      GC線程:   執(zhí)行實(shí)際的垃圾回收工作(標(biāo)記、清除、壓縮)
      

      原因2:用戶(hù)線程在 GC 期間被暫停

      // 用戶(hù)線程在 GC 期間的狀態(tài)
      while (GC.IsInProgress())
      {
          // 用戶(hù)線程被暫停,不執(zhí)行任何代碼
          // SampleProfiler 無(wú)法采樣到 GC 相關(guān)活動(dòng)
      }
      

      原因3:采樣頻率問(wèn)題

      // GC 調(diào)用可能很快完成
      GC.Collect(0, GCCollectionMode.Forced);  // 調(diào)用本身很快
      GC.WaitForPendingFinalizers();           // 等待時(shí)間可能不被采樣
      

      那就是抓取不到了,這是個(gè)問(wèn)題。

      image

      可以看到主動(dòng)調(diào)用才抓到這么幾次,難道只消耗著一點(diǎn)cpu嗎?

      image

      那么cpu到底被gc消耗掉了還是被用戶(hù)線程消耗掉了,這個(gè)怎么判斷呢?通過(guò)我們打印gc時(shí)間還是消耗了很多cpu呢,那么怎么看呢?

      那么gc 問(wèn)題就有專(zhuān)門(mén)的工具了,一個(gè)是gc-verbose,dotnet-counters.

      下面來(lái)試一下dotnet-counters。

      重新跑這個(gè)例子:

      dotnet-counters collect --process-id 20084 --refresh-interval 5 --duration 60 --output counters.csv
      

      然后可以看到結(jié)果,因?yàn)樽ト〉谋容^多,這里只用一個(gè)來(lái)說(shuō)明:

      08/07/2025 16:32:28,System.Runtime,CPU Usage (%),Metric,0
      08/07/2025 16:32:28,System.Runtime,Working Set (MB),Metric,1078.317056
      08/07/2025 16:32:28,System.Runtime,GC Heap Size (MB),Metric,1032.561848
      08/07/2025 16:32:28,System.Runtime,Gen 0 GC Count (Count / 5 sec),Rate,373
      08/07/2025 16:32:28,System.Runtime,Gen 1 GC Count (Count / 5 sec),Rate,233
      08/07/2025 16:32:28,System.Runtime,Gen 2 GC Count (Count / 5 sec),Rate,88
      08/07/2025 16:32:28,System.Runtime,Gen 0 GC Budget (MB),Metric,6
      08/07/2025 16:32:28,System.Runtime,ThreadPool Thread Count,Metric,2
      08/07/2025 16:32:28,System.Runtime,Monitor Lock Contention Count (Count / 5 sec),Rate,1
      08/07/2025 16:32:28,System.Runtime,ThreadPool Queue Length,Metric,0
      08/07/2025 16:32:28,System.Runtime,ThreadPool Completed Work Item Count (Count / 5 sec),Rate,0
      08/07/2025 16:32:28,System.Runtime,Allocation Rate (B / 5 sec),Rate,1040950952
      08/07/2025 16:32:28,System.Runtime,Number of Active Timers,Metric,0
      08/07/2025 16:32:28,System.Runtime,GC Fragmentation (%),Metric,0.8735136169672377
      08/07/2025 16:32:28,System.Runtime,GC Committed Bytes (MB),Metric,1043.730432
      08/07/2025 16:32:28,System.Runtime,Exception Count (Count / 5 sec),Rate,0
      08/07/2025 16:32:28,System.Runtime,% Time in GC since last GC (%),Metric,99
      08/07/2025 16:32:28,System.Runtime,Time paused by GC (ms / 5 sec),Rate,5683.659000000001
      08/07/2025 16:32:28,System.Runtime,Gen 0 Size (B),Metric,0
      08/07/2025 16:32:28,System.Runtime,Gen 1 Size (B),Metric,0
      08/07/2025 16:32:28,System.Runtime,Gen 2 Size (B),Metric,1024966792
      08/07/2025 16:32:28,System.Runtime,LOH Size (B),Metric,16646536
      08/07/2025 16:32:28,System.Runtime,POH (Pinned Object Heap) Size (B),Metric,32712
      08/07/2025 16:32:28,System.Runtime,Number of Assemblies Loaded,Metric,11
      08/07/2025 16:32:28,System.Runtime,IL Bytes Jitted (B),Metric,15131
      08/07/2025 16:32:28,System.Runtime,Number of Methods Jitted,Metric,153
      08/07/2025 16:32:28,System.Runtime,Time spent in JIT (ms / 5 sec),Rate,1605.8994
      

      首先看一下gc評(píng)率:

      08/07/2025 16:32:28,System.Runtime,Gen 0 GC Count (Count / 5 sec),Rate,373
      08/07/2025 16:32:28,System.Runtime,Gen 1 GC Count (Count / 5 sec),Rate,233
      08/07/2025 16:32:28,System.Runtime,Gen 2 GC Count (Count / 5 sec),Rate,88
      

      線上5秒,發(fā)生了很多的gc。

      08/07/2025 16:32:28,System.Runtime,% Time in GC since last GC (%),Metric,99
      08/07/2025 16:32:28,System.Runtime,Time paused by GC (ms / 5 sec),Rate,5683.659000000001

      這里表示gc 5秒占用的時(shí)間是5683.659000000001,這個(gè)應(yīng)該是計(jì)算有點(diǎn)問(wèn)題的。

      Time in GC since last GC 這個(gè)是這一次gc,占用到距離上一次gc的百分比。

      TimeInGCPercent = (TotalGCPauseTime / TotalTimeSinceLastGC) * 100

      高百分比(如 99%)

      // 表示應(yīng)用程序幾乎一直在進(jìn)行 GC
      // 應(yīng)用程序線程大部分時(shí)間被暫停
      // 用戶(hù)體驗(yàn)很差,響應(yīng)性很低
      

      低百分比(如 5%)

      // 表示 GC 占用時(shí)間很少
      // 應(yīng)用程序線程大部分時(shí)間在執(zhí)行業(yè)務(wù)邏輯
      // 用戶(hù)體驗(yàn)良好,響應(yīng)性好
      

      3. CPU 使用分析

      • CPU Usage:7.7-8.4%(相對(duì)穩(wěn)定)
      • ThreadPool Thread Count:1-2個(gè)線程

      分析:CPU 使用率適中,但 GC 工作占用了大量時(shí)間。

      后臺(tái) GC 指標(biāo)

      • 數(shù)據(jù)中沒(méi)有顯示 gc-background-gc-countgc-concurrent-gc-count
      • 所有 GC 都是阻塞性的

      內(nèi)存分配

      • Allocation Rate:31MB-1GB/5秒(變化很大)
      • GC Heap Size:約 1032MB(相對(duì)穩(wěn)定) // 只是gc托管的資源
      • Working Set:1057-1087MB(緩慢增長(zhǎng))// 程序占用系統(tǒng)全部的資源

      內(nèi)存分布

      • Gen 0 Size:0-11KB(大部分時(shí)間為空)
      • Gen 1 Size:0-6MB(偶爾有對(duì)象)
      • Gen 2 Size:約 1024MB(主要內(nèi)存占用)
      • LOH Size:約 16MB(大對(duì)象堆) # 這個(gè)需要看一下,large object heap
      • POH Size:32KB(固定對(duì)象堆) # pined object heap,不用管比較小

      分析:大部分對(duì)象都被提升到 Gen 2,說(shuō)明應(yīng)用程序在創(chuàng)建長(zhǎng)期存活的對(duì)象。

      這樣就可以大量gc問(wèn)題,還有內(nèi)存的關(guān)系了。

      結(jié)

      在確定是用戶(hù)時(shí)間消耗cpu的時(shí)候,需要查看dotnetcount 查看gc,和查看火焰圖一起看,這樣才是合理的,因?yàn)榛鹧鎴D比較難看到gc,尤其是專(zhuān)有g(shù)c。

      posted @ 2025-08-07 18:21  敖毛毛  閱讀(26)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 午夜爽爽爽男女免费观看影院| 国产精品涩涩涩视频网站| 青青草无码免费一二三区| 爱性久久久久久久久| 国产99在线 | 亚洲| 西乌珠穆沁旗| 日韩av毛片福利国产福利| 亚洲成人四虎在线播放| 国产超碰人人做人人爱ⅴa| 亚洲码亚洲码天堂码三区| 亚洲人妻中文字幕一区| 性视频一区| 17岁日本免费bd完整版观看| 国产精品午夜福利导航导| 在线免费不卡视频| 少妇被无套内谢免费看| 亚洲人成网站在线播放动漫| 另类图片亚洲人妻中文无码| 国产成人一区二区不卡| 在线天堂最新版资源| FC2免费人成在线视频| 茂名市| 乱老年女人伦免费视频| 99在线精品国自产拍中文字幕| 日本一二三区视频在线| 无码日韩精品一区二区免费| 日本老熟女一二三区视频| 久久国产成人午夜av影院| 国内精品免费久久久久电影院97| 国产午夜福利大片免费看| 国产偷国产偷亚洲清高动态图| 成人一区二区人妻不卡视频| 久久精品国产再热青青青| 日韩加勒比一本无码精品| 麻豆国产成人AV在线播放| 国语做受对白XXXXX在线| 色二av手机版在线| 久久亚洲精品成人综合网| 精品人妻伦九区久久aaa片| 无码精品人妻一区二区三区中| 99久久精品国产一区二区蜜芽|