在本教程中,我们将看到如何使用dotmemory定位和固定在你的应用程序的内存泄漏。但在开始之前,让我们在一个内存泄漏是一致的。

内存泄漏是什么?

根据维基百科,内存泄漏是由于不正确的内存管理时,”一个对象是存储在内存中,但不能被运行代码访问。”此外,“内存泄漏加起来的时间,如果他们不清理,系统最终耗尽内存。”

实际上,如果我们将严格按照上述定义,“经典”的内存泄漏是不可能的网络应用程序。垃圾收集器(GC)完全控制内存释放并删除所有的对象不能被访问的代码。此外,在应用程序关闭时,GC完全释放由应用程序所占用的内存。然而,2点#(内存耗尽由于泄漏)是真实的。当然,这不会破坏系统,但是迟早,应用程序将提高OutOfMemory例外。

为什么会发生这种事?问题是,GC只收集未引用的对象。如果有一个对象的引用你不知道,GC不会采集对象。因此,在固定的内存泄漏的主要策略是确定的对象,加起来的时间(导致泄露)以及对象保留前的记忆。

让我们试试这个策略在我们的样本中应用固定泄漏。

目录

示例应用程序

步骤1。运行剖面

步骤2。得到的快照

步骤3。比较快照

步骤4。分析快照

步骤5。检查其他泄漏

示例应用程序

再次,应用程序将使用我们的教程是康威的生命游戏。请下载并解压存档在不久的将来。

让我们假设我们要返回一些钱花在生命发展的博弈决定添加几个窗口,显示各种广告的用户。在最坏的做法,我们显示我们的广告窗口每次用户启动游戏人生(点击开始按钮)。当用户点击一个横幅,他/她将被重定向到一些网站和广告窗口关闭(用户也可以关闭该窗口使用标准的关闭按钮,不过那不是我们真正想要的)。改变广告,广告中使用Windows计时器(基于dispatchertimer类)。

你可以在adwindow.cs文件中看到的adwindow类的实现。

 

因此,添加功能,现在是测试它的最佳时间。让我们跑dotmemory确保广告窗口不影响应用程序的内存使用(换句话说,它是正确地分配和收集)。

步骤1。运行剖面

1。打开在Visual Studio解决游戏人生。

2。使用菜单dotmemory |剖面启动项目运行dotmemory。

 

这将打开系统配置窗口。

3在探查器配置窗口:

a.打开收集创作的堆栈跟踪每n个对象。这将创造的堆栈跟踪信息记录。我们需要这些信息来确定什么叫创造一个特定的对象。

b.将立即开始收集。这会告诉dotmemory开始收集创作的堆栈跟踪,在应用程序启动。

c.这里就是窗口应该看上去像你指定的所有选项后:

 

4。单击“运行”开始分析会话。这将运行我们的应用程序和打开dotmemory主要分析页。

 

步骤2得到的快照

一旦应用程序运行,我们可以得到一个内存快照。我们要测试我们的新的广告窗口和它们如何影响内存的使用,我们需要两个快照:一个在窗口显示(我们将使用快照作为比较的基础),和另一个广告窗口关闭后。第二快照需要确保GC除去我们的窗户从记忆。

1.  单击应用程序启动按钮开始游戏。广告窗口将出现。

 

2.  点击进入dotmemory快照按钮。

 

这将捕获的数据和添加快照快照区。得到的快照,不中断的分析过程,从而使我们能够得到另一个快照。

3。在我们的应用程序的广告窗口关闭。

4。点击进入dotmemory快照按钮得到再一次快照。

5。通过关闭应用程序的生命游戏结束分析会话。

主页包含两个快照。

 

步骤3。比较快照

现在,我们将比较和对比两个收集的快照。我们希望看到什么?如果一切运行良好,门窗应在第一个快照而缺席的第二。让我们看一看。

 

1。单击“添加到每个快照添加到比较区域比较。为了在你添加快照是不重要的dotmemory总是使用旧的快照作为比较基础。

 

2。单击“比较在对照区。这将打开比较论。

 

该视图显示多少个类的对象被创建(新的对象列)和删除(死对象列)之间的快照。幸存下来的对象显示多少对象在垃圾回收,或者,换句话说,在快照的存在。

 

目前,我们的兴趣在adwindow类。

 

3。放松对adwindow类的发现,让我们把所有对象所属的命名空间。要做到这一点,单击“组中的视图列表中的命名空间。

 

4打开gameoflife命名空间。

 

那是什么?两个gameoflife.adwindow对象中幸存下来的对象列,这意味着广告窗口还活着。我们关闭窗口后,对象应该是从堆中删除。然而,防止它们被收集的东西。

 

现在是时候开始我们的调查,找出为什么我们的窗户没有被删除!

 

步骤4分析快照

在教程中提到1 -开始dotmemory *,你应该把你的工作在dotmemory作为犯罪调查。你通过一个巨大的嫌疑人名单开始你的调查(对象)和不断缩小的列表,直到你找到一个使问题。你的推理是在所谓的分析路径上的dotmemory窗口的左侧。

让我们在行动中尝试这种方法。

1.  打开了gameoflife.adwindow对象集合组成的两个对象。为此,请单击“下一步”的gameoflife.adwindow类2号在存活的对象列。

 

作为对象存在于快照,dotmemory将提示您指定的快照对象应显示。当然,我们感兴趣的最后快照,窗应该被收集。

2。选择打开“幸存物”在新的快照并单击“确定”。

 

这将显示对象集”的adwindow类,存在于快照# 1和# 2”在类型列表中查看所有对象。根据这一观点,对象集包含2个实例与浅的大小的952。这些例子只保留其他对象的10676。总的大小

 

我们的兴趣不在adwindow对象本身,但在那些保留我们的广告窗口内存。解决这个问题,我们要看所选对象设置使用组”的观点。这将给我们的统治者——对象在内存中只保留我们的广告窗口。

3。查看对象组”列表中,单击视图列表”组的。

 

正如你所看到的,广告窗口保留在内存中的事件处理程序,其中,反过来,是由dispatchertimer类实例的引用。让我们继续我们的调查,试图找出那些定时器对象的更多细节。

4。右键单击设置列表中的dispatchertimer对象并选择打开此对象集。

 

这将在类型列表视图中打开dispatchertimer对象设置*。现在,我们的目的是了解这些计时器涉及adwindow对象。换句话说,如何借鉴我们的广告窗口定时器。得到这个信息,我们应该更深入和采取的dispatchertimer类的具体实例一看。

5。打开实例视图,双击任何dispatchertimer类的实例。无论你选择哪一个,因为他们显然与我们的广告窗口相同的关系。

 

默认情况下,该实例是使用即将离任的参考视图。这种观点是用来获取实例的域和参考资料。

 

你还记得,广告窗口保留由事件处理程序,其中,反过来,是由dispatchertimer实例参考。即将离任的参考视图显示了如何发生这种情况——广告窗口通过Tick事件处理程序的引用。看来,adwindow实例订阅的定时器Tick事件。让我们在这看代码。

6。快速地在代码中找到所需的电话,让我们用dotmemory。简单地切换到创作的堆栈跟踪视图。

 

它在这里!那实际上创建计时器堆栈的最新电话是adwindow构造函数。让我们在代码中找到它。

7。切换到Visual Studio的gameoflife溶液和定位adwindow构造函数。

 

你可以看到,我们的广告窗口使用changeads的方法来处理事件。

 

但广告窗口保存在内存中我们后关闭它是为什么?问题是,我们订了窗口的计时器事件却忘了取消它。因此,这次泄漏的修复很简单:我们需要添加一些unsubscribe()方法可称为关闭广告窗口时。事实上,代码已经包含了这样的方法,和所有您需要做的是取消该unsubscribe();在窗口的onclosed事件线。最后,代码看起来应该像这样:

 

8。现在,以确保泄漏是固定的,让我们再解决方案和运行分析。单击dotmemory的菜单和重复步骤2配置项。得到的快照和步骤3。比较快照。

 

 

就是这样!该adwindow实例正在死去的对象列这意味着他们的第二次快照的时间成功地收集。泄漏是固定的!

说实话,这种泄漏也经常发生。通常,事实上,这dotmemory自动检查您的应用程序的这种类型的漏洞。

因此,如果你打开包含漏看检查区域在快照概述页第二快照,你会注意到有一个事件处理程序dotmemory泄漏检查已经包含了我们的adwindow对象。

 

步骤5。检查其他泄漏

我们固定的事件句柄泄漏,和广告窗口现在用气相色谱法成功地收集。但是什么导致问题的定时器吗?如果工作很好,计时器应收集也应该在第二个快照缺席。让我们看一看。

  1. 在dotmemory打开第二个快照。为此,请单击gameoflife.exe步(你的调查开始)在分析路径,然后单击“快照# 2连杆的第二快照。

 

2.  开放式列表视图快照点击链接的最大尺寸。

 

3.  在开放式列表视图,在过滤字段中输入dispatchertimer。这将名单减少,只留下对象包含此模式在其类别名称。

 

你可以看到,有8dispatchertimer堆中的对象。

4.  打开设置双击的dispatchertimer对象。

 

这将在类型列表视图中打开设置。现在,我们需要确保这一套不包含由广告窗口创建计时器。当定时器在adwindow构造函数创建的,最简单的方法就是看设置使用组创作StackTrace视图。

5。请单击视图列表后的痕迹,链接(下组创建堆栈跟踪)。

 

这将显示我们需要从一个直接创建对象,降到堆栈中的第一个电话。

 

不幸的是,这adwindow。医生(窗口的所有者)称仍在这里,这意味着该调用创建计时器没有收集。他们的存在在快照不管事实的广告窗口被关闭,从内存中删除。这看起来像一个内存泄漏,我们应该分析。

6。双击adwindow因子(窗口的所有者)调用。

 

dotmemory将显示我们的对象集(由两个定时器)在类型列表视图。

 

找出什么保留在内存中的定时器,让我们看看组”的观点。

 

7。在视图列表中的“组”。

 

统治者列表只包含一行,不完全保留的对象,这意味着每个定时器是由一个以上的对象保留在内存中。

 

在这种情况下,最好的办法是看这样的“不完全保留的对象主要保留路径。为了这个目的,dotmemory有观点称为组类似的保留。

 

8。在视图列表中单击组类似的保留。

 

 

集团通过类似的保留视图组对象在由他们的保留路径相似的一组。此外,该视图显示为每个组的两个最不同的保存路径。通常情况下,这是足够的了解是什么阻止你从收集的对象。

9。请单击列表中的任何计时器。

 

你可以看到,我们的前辈有稍微不同的保存路径。事实上,它们的区别仅在一个额外的priorityitem对象;因此,在我们的例子中没有大的差异的定时器实例分析。

 

我们的前辈第一保留路径引导我们的dispatchertimer列表,这是全球性的,存储在应用程序的所有定时器。第二种方法表明,计时器也由dispatcheroperationcallback对象保留。这个对象代表,创造了当您运行计时器。这意味着计时器还在运行。dispatchertimer类的一个奇怪的事是,实例是从全球定时器列表后,计时器停止拆除。因此,堵漏,我们必须在广告窗口关闭停止计时器。让我们在代码中做这个!

 

10。打开包含的adwindow课实施adwindow.cs文件。事实上,该修补程序将很简单。我们需要做的是添加adtimer。stop();线到unsubscribe()方法。在固定的方法,应该是这样的:

 

11重新生成解决方案。

 

12。单击“配置项在dotmemory的菜单和重复步骤2。得到的快照和步骤3。比较快照。

13。在类型列表视图中打开第二个快照。

 

正如你所看到的,只有6 dispatchertimer对象而不是8在我们确定泄漏的快照。确保GC收集的广告窗口使用定时器,让我们来看看这些计时器从组创作StackTrace视图。

 

14。双击dispatchertimer对象,然后在视图列表中点击链接后的痕迹。

 

在列表中没有adwindow构造函数,这意味着泄漏已被成功地固定。

 

当然,这种泄漏似乎并不重要,尤其是我们的应用程序。如果我们不使用dotmemory,我们可能没有注意到的问题。然而,在其他的应用程序(例如,服务器端的工作24 / 7)泄漏可以表现本身造成OutOfMemory例外一定时间后。

 

posted on 2014-11-18 17:47  MarryQ  阅读(3717)  评论(1编辑  收藏  举报