Visual Studio 2013 新功能 Memory Dump 分析器


本文為 Dennis Gao 原創技術文章,發表於博客園博客,未經作者本人允許禁止任何形式的轉載。

TechEd2013 發現新功能

12月5日和6日,在國家會議中心參加了微軟的 TechEd2013 技術大會,了解了很多微軟所提供的軟件新功能和新技術。

在上面的圖中描述了在 Visual Studio 2013 中提供了新的功能 .NET Memory Dump Analysis,在具體的 Visual Studio 2013 新功能介紹的 Session 看到了實際的演示。當時感覺這個新功能對開發人員太有幫助了,因為使用 WinDbg 進行內存泄漏等問題排查總是一種痛苦。如果能在 Visual Studio 中包含類似的功能就再好不過了。

准備嘗鮮 .NET Memory Dump Analysis

回到家,自然是想使用 Visual Studio 2013 直接上手實際體驗下。

在創造了一個 Dump 文件之后,使用 Visual Studio 2013 直接打開,

結果發現,在 Actions 處少一個 "Debug Managed Memory" 按鈕。

它應該長這個樣子才對:

Google 之后發現原來我使用的是 Visual Studio 2013 Premium 版本,而該功能只有在 Visual Studio 2013 Ultimate 版本中才支持。

公司的 MSDN 訂閱選的是 Premium ,比較了下與 Ultimate 的區別,價格果真差的很大。

 此時,我選擇了安裝個 Windows 7 SP1 虛擬機,並安裝 Visual Studio 2013 Ultimate 的試用版。

遭遇 Visual Studio 2013 的 Known Issue

顯然,安裝上 Visual Studio 2013 Ultimate 之后,再打開 Dump 文件,就可以成功看到 Actions 中的 "Debug Managed Memory" 按鈕。

點擊該按鈕,等待 Heap View 顯示。

什么?白屏?一萬只馬飄過。

這可真是郁悶,折騰了半天都沒反應。

於是只能問 Google 了,顯然,新的功能暫時沒什么人用,也搜不到什么有用的討論。

終於,當搜索關鍵詞修改為 “Visual Studio 2013 Debug Managed Memory is not work” 時,有用的信息出現了。

打開一看,這居然是一個 Visual Studio 2013 Known Issue,基本就是要求安裝 IE10 或以上的版本才能使用此功能。

解決辦法,當然就是安裝新版 IE,立馬下載安裝 IE11。新裝的虛擬機中的 Windows 7 默認的還是 IE8 。

使用 Dump 文件比較功能

這一次,成功看到了 Heap View。

在 Compare to 中選擇一個之前的 Dump 文件作為對比,即可查看兩個文件時間的內存變化。

Inclusive Size

在 Heap View 中,有一列為 Inclusive Size (Bytes)。

其包含所顯示對象引用的所有對象內存占用的總和。下面的圖標展示了內存占用大小的計算過程。

Object Type

Count

Size (Bytes)

Inclusive Size (Bytes)

Customer

1

100

400

Address

1

50

200

String

2

150

150

Byte[]

1

100

100

 

 

 

 

 

 

 

 

 

Address 對象的 Inclusive Size = Address (50 bytes) + String (50 bytes) + Byte[] (100 bytes) = 200 bytes

Customer 對象的 Inclusive Size = Address Inclusive Size (200 bytes) + String (100 bytes) + Customer (100 bytes) = 400 bytes

Inclusive Size Diff

在使用 Dump 比較功能后,顯示的列中會出現 "Inclusive Size Diff",用來描述在兩個 Dump 文件采集的時間點時,Inclusive Size 的變化。

View Setting

在 Dump 比較的界面中,我們可以看到 View Settings 選項。

  • Just My Code :顧名思義,僅顯示用戶代碼。
  • Collapse Small Objects :隱藏小對象。

這里需要描述下,小對象隱藏后的 Inclusive Size 的計算方式。

實際上,會將被隱藏的小對象的大小累加到父對象上。

仍然使用上面的圖例進行計算。

我們假設 String 和 Byte[] 被隱藏,在隱藏小對象后,

Object Type

Count

Size (Bytes)

Inclusive Size (Bytes)

Customer

1

200

400

Address

1

200

200

 

 

 

 

 

 

Paths To Root View

點擊 Heap View 列表中的某一個 Object Type,在 Paths To Root 中會通過級聯方式顯示對象的引用關系。

這用於顯示,是哪個對象引用導致該對象沒有被垃圾回收。

References View

References View 用於顯示,這個對象都引用了哪些對象。

測試用代碼

 1 using System;
 2 using System.Collections.Concurrent;
 3 using System.Collections.Generic;
 4 using System.Threading;
 5 
 6 namespace TestDebugMemoryDumpFile
 7 {
 8   class Program
 9   {
10     static ConcurrentQueue<Tree> _leakedTrees = new ConcurrentQueue<Tree>();
11 
12     static void Main(string[] args)
13     {
14       List<string> fruits = new List<string>() // 6 items
15       { 
16         "Apple", "Orange", "Pear", "Banana", "Peach", "Hawthorn",
17       };
18 
19       Random random = new Random();
20       while (true)
21       {
22         string fruitName = fruits[random.Next(0, 5)];
23         Tree fruitTree = new Tree(fruitName);
24         BuildFruitTree(fruitTree, 100); // 100M
25         _leakedTrees.Enqueue(fruitTree);
26 
27         Console.WriteLine("Added    [{0}] on [{1}]...", 
28           fruitTree.Name,
29           DateTime.Now.ToString(@"yyyy-MM-dd HH:mm:ss.ffffff"));
30 
31         Thread.Sleep(TimeSpan.FromSeconds(5));
32       }
33     }
34 
35     private static void BuildFruitTree(Tree fruitTree, int leafCount)
36     {
37       Console.WriteLine("Building [{0}] on [{1}]...", 
38         fruitTree.Name, 
39         DateTime.Now.ToString(@"yyyy-MM-dd HH:mm:ss.ffffff"));
40 
41       for (int i = 0; i < leafCount; i++) // size M
42       {
43         Leaf<byte[]> leaf = new Leaf<byte[]>(Guid.NewGuid())
44         {
45           Content = CreateContentSizeOfOneMegabyte()
46         };
47         fruitTree.Leaves.Add(leaf);
48       }
49     }
50 
51     private static byte[] CreateContentSizeOfOneMegabyte()
52     {
53       byte[] content = new byte[1024 * 1024]; // 1 M
54       for (int j = 0; j < content.Length; j++)
55       {
56         content[j] = 127;
57       }
58       return content;
59     }
60   }
61 
62   internal class Tree
63   {
64     public Tree(string name)
65     {
66       Name = name;
67       Leaves = new List<Leaf<byte[]>>();
68     }
69 
70     public string Name { get; private set; }
71     public List<Leaf<byte[]>> Leaves { get; private set; }
72   }
73 
74   internal class Leaf<T>
75   {
76     public Leaf(Guid id)
77     {
78       Id = id;
79     }
80 
81     public Guid Id { get; private set; }
82     public T Content { get; set; }
83   }
84 }

參考資料

本文為 Dennis Gao 原創技術文章,發表於博客園博客,未經作者本人允許禁止任何形式的轉載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM