Bloatview¶
BloatView 是一款显示累积内存使用情况和泄漏信息的工具。如果发现泄漏,可以使用 引用计数跟踪和平衡 来查找根本原因。
如何使用 BloatView 构建¶
使用 --enable-debug
或 --enable-logrefcnt
构建。
如何使用 BloatView 运行¶
可以使用两个环境变量。
XPCOM_MEM_BLOAT_LOG
如果设置,则会在程序退出时以及每次调用 nsTraceRefcnt::DumpStatistics
时打印 bloat 日志。此日志包含有关泄漏和膨胀(也称为使用情况)的数据。
XPCOM_MEM_LEAK_LOG
这类似于 XPCOM_MEM_BLOAT_LOG
,但将日志限制为仅显示有关泄漏的数据。
您可以将这些环境变量设置为以下任何值。
1 - 将日志输出到标准输出。
2 - 将日志输出到标准错误。
文件名 - 将日志写入文件。
读取单个 bloat 日志¶
完整的 BloatView 输出包含每个类的分配和引用计数统计信息,并提供有关按类细分的内存泄漏量的总数量。以下是 BloatView 输出示例。
== BloatView: ALL (cumulative) LEAK AND BLOAT STATISTICS, tab process 1862
|<----------------Class--------------->|<-----Bytes------>|<----Objects---->|
| | Per-Inst Leaked| Total Rem|
0 |TOTAL | 17 2484|253953338 38|
17 |AsyncTransactionTrackersHolder | 40 40| 10594 1|
78 |CompositorChild | 472 472| 1 1|
79 |CondVar | 24 48| 3086 2|
279 |MessagePump | 8 8| 30 1|
285 |Mutex | 20 60| 89987 3|
302 |PCompositorChild | 412 412| 1 1|
308 |PImageBridgeChild | 416 416| 1 1|
第一行告诉您泄漏进程的进程 ID 以及进程类型。
以下是列的解释方式。
第一个数字列 是泄漏类的索引。
类 - 有问题的类的名称(截断为 20 个字符)。
每个实例的字节数 - 如果您要编写
sizeof(Class)
,则返回的字节数。请注意,此数字不反映类持有的任何内存,例如内部缓冲区等。(例如,对于nsString
,您将看到头结构的大小,而不是字符串内容的大小!)泄漏字节数 - 每个实例的字节数乘以泄漏的对象数:(每个实例的字节数)x(剩余对象数)。使用此数字查找最严重的违规者。(应为零!)
对象总数 - 给定类分配的对象总数。
剩余对象数 - 给定类分配的对象中未删除的对象数。(应为零!)
值得关注的事项
您的类是否在列表中? - 看!如果它们不在,那么您没有为 xpcom 对象使用
NS_IMPL_ADDREF
和NS_IMPL_RELEASE
(或调用它们的NS_IMPL_ISUPPORTS
),或者为非 xpcom 对象使用MOZ_COUNT_CTOR
和MOZ_COUNT_DTOR
。您的类不在列表中 不是 可以接受的。这意味着没有人查看它们,我们无法判断是否有人引入了泄漏。(请参阅 下文,了解如何解决此问题。)您的类的泄漏字节数应为零! - 我还需要多说吗?如果不是,您应该使用其他工具来修复它。
剩余对象数可能不等于对象总数。 这可能表示手写 Release 方法(未使用 nsTraceRefcnt.h 中的
NS_LOG_RELEASE
宏),或者您可能只是没有释放分配的任何实例。这些类型的泄漏很容易修复。对象总数可能为 1。 这可能表示全局变量或服务。通常,这将具有大量的引用计数。
如果发现泄漏,可以使用 引用计数跟踪和平衡 来查找根本原因。
合并和排序 bloat 日志¶
您可以通过运行以下程序在浏览器中查看一个或多个 bloat 日志。
perl tools/bloatview/bloattable.pl *log1* *log2* \... *logn* >
*htmlfile*
这将生成一个 HTML 文件,其中包含类似于以下内容的表格(但添加了 JavaScript,以便您可以按列对数据进行排序)。
Byte Bloats
---------- ---------------- --------------------------
Name File Date
blank `blank.txt` Tue Aug 29 14:17:40 2000
mozilla `mozilla.txt` Tue Aug 29 14:18:42 2000
yahoo `yahoo.txt` Tue Aug 29 14:19:32 2000
netscape `netscape.txt` Tue Aug 29 14:20:14 2000
---------- ---------------- --------------------------
这些数字不包括 malloc 分配的数据,例如字符串内容。
单击列标题可按该列排序。单击类名可查看该类的详细信息。
-------------------- --------------- ----------------- --------- --------- ---------- ---------- ------------------------------- --------- -------- ---------- ---------
Class Name Instance Size Bytes allocated Bytes allocated but not freed
blank mozilla yahoo netscape Total blank mozilla yahoo netscape Total
TOTAL 1754408 432556 179828 404184 2770976
nsStr 20 6261600 3781900 1120920 1791340 12955760 222760 48760 13280 76160 360960
nsHashKey 8 610568 1842400 2457872 1134592 6045432 32000 536 568 1216 34320
nsTextTransformer 548 8220 469088 1414936 1532756 3425000 0 0 0 0 0
nsStyleContextData 736 259808 325312 489440 338560 1413120 141312 220800 -11040 94944 446016
nsLineLayout 1100 2200 225500 402600 562100 1192400 0 0 0 0 0
nsLocalFile 424 558832 19928 1696 1272 581728 72080 1272 424 -424 73352
-------------------- --------------- ----------------- --------- --------- ---------- ---------- ------------------------------- --------- -------- ---------- ---------
第一组列,分配的字节数,显示第一个日志文件 (blank.txt
) 中分配的内存量,第一个日志文件和第二个日志文件 (mozilla.txt
) 之间的差异,第二个日志文件和第三个日志文件 (yahoo.txt
) 之间的差异,第三个日志文件和第四个日志文件 (netscape.txt
) 之间的差异,以及第四个日志文件中分配的内存总量。这些列提供了内存分配器工作强度的概念,但它们并不表示工作集的大小。
第二组列,分配但未释放的字节数,显示通过从分配的内存量中减去释放的内存量获得的净内存增益或损失。
显示对象和显示引用按钮显示相同的统计信息,但计数对象或 AddRef
的引用而不是字节。
比较 Bloat 日志¶
您还可以比较任何两个 bloat 日志(程序关闭时产生的日志或写入 bloatlogs 目录的日志),方法是运行以下程序。
`perl tools/bloatview/bloatdiff.pl` <previous-log> <current-log>
这将为您提供以下格式的输出
Bloat/Leak Delta Report
Current file: dist/win32_D.OBJ/bin/bloatlogs/all-1999-10-22-133450.txt
Previous file: dist/win32_D.OBJ/bin/bloatlogs/all-1999-10-16-010302.txt
--------------------------------------------------------------------------
CLASS LEAKS delta BLOAT delta
--------------------------------------------------------------------------
TOTAL 6113530 2.79% 67064808 9.18%
StyleContextImpl 265440 81.19% 283584 -26.99%
CToken 236500 17.32% 306676 20.64%
nsStr 217760 14.94% 5817060 7.63%
nsXULAttribute 113048 -70.92% 113568 -71.16%
LiteralImpl 53280 26.62% 75840 19.40%
nsXULElement 51648 0.00% 51648 0.00%
nsProfile 51224 0.00% 51224 0.00%
nsFrame 47568 -26.15% 48096 -50.49%
CSSDeclarationImpl 42984 0.67% 43488 0.67%
此“增量报告”显示泄漏违规者,从泄漏最多到泄漏最少进行排序。增量数字显示运行之间泄漏量和膨胀量的百分比变化(负数更好!)。膨胀数是通过将给定类的分配对象总数乘以类大小来确定的指标。请注意,虽然这并不一定是在任何给定时间消耗的内存量,但它确实指示了我们正在消耗多少内存。通常内存越多,性能和占用空间就越差。百分比 99999.99% 将显示为表示“无限”量的泄漏。当以前没有泄漏的东西现在开始泄漏时,就会发生这种情况。
BloatView 和持续集成¶
BloatView 在 Mozilla 在持续集成下运行的许多测试套件的调试版本上运行。如果发生新的泄漏,它将触发测试作业失败。
BloatView 的输出文件还可以显示泄漏对象是在哪里分配的。为此,应将 XPCOM_MEM_LOG_CLASSES
环境变量设置为 BloatView 表格中的类名
XPCOM_MEM_LOG_CLASSES=MyClass mach mochitest [options]
可以通过将 XPCOM_MEM_LOG_CLASSES
设置为以逗号分隔的名称列表来指定多个类名
XPCOM_MEM_LOG_CLASSES=MyClass,MyOtherClass,DeliberatelyLeakedClass mach mochitest [options]
测试套件脚本通常接受一个 --setenv
选项来指定环境变量,在某些情况下这可能更方便
mach mochitest --setenv=XPCOM_MEM_LOG_CLASSES=MyClass [options]
要在自动化中获取分配堆栈,您可以将相应的 --setenv
选项添加到您感兴趣的平台的测试配置中。这些配置位于 testing/mozharness/configs/
中。您可能需要修改的最可能的配置列在下面
Linux:
unittests/linux_unittest.py
Mac:
unittests/mac_unittest.py
Windows:
unittests/win_unittest.py
Android:
android/androidarm.py
如何为 BloatView 为您的对象添加检测¶
首先,如果您的对象是 xpcom 对象,并且您使用 NS_IMPL_ADDREF
和 NS_IMPL_RELEASE
(或其变体)宏来实现您的 AddRef
和 Release
方法,那么您无需执行任何操作。默认情况下,这些宏直接支持 refcnt 日志记录。
如果您的对象不是 xpcom 对象,则需要进行一些手动编辑。以下示例代码显示了必须执行的操作
MyType::MyType()
{
MOZ_COUNT_CTOR(MyType);
...
}
MyType::~MyType()
{
MOZ_COUNT_DTOR(MyType);
...
}