有多个可供在代码中指定的 discover API 和环境变量。
Oracle Solaris Studio 12.4 实现了六个新的可以从程序调用以接收内存泄漏和内存分配信息的 discover 函数。这些函数将信息输出到 stderr。缺省情况下,discover 会在程序输出的末尾输出包含程序中内存泄漏的最终内存报告。要使用这些 API,应用程序的源文件需要包含 discover 的头文件:#include <discoverAPI.h>。
这些函数及其报告的内容如下所示:
报告所有内存分配。
报告以前未报告的所有内存分配。
将迄今为止的所有内存分配标记为已报告。
报告所有内存泄漏。
报告以前未报告的所有内存泄漏。
将迄今为止的所有内存泄漏标记为已报告。
本节介绍一些使用 discover API 的方法。
对于在您的代码中指定的每个函数,discover 会报告内存分配位置的堆栈。内存泄漏是在程序中无法访问的已分配内存。
以下示例显示如何使用这些 API:
$ cat -n tdata.C 1 #include <discoverAPI.h> 2 3 void foo() 4 { 5 int *j = new int; 6 } 7 8 int main() 9 { 10 foo(); 11 discover_report_all_leaks(); 12 13 foo(); 14 discover_report_unreported_leaks(); 15 16 return 0; 17 } $ CC -g tdata.C $ discover -w - a.out $ a.out
以下示例显示了预期输出。
******** discover_report_all_leaks() Report ******** 1 allocation at 1 location left on the heap with a total size of 4 bytes LEAK 1: 1 allocation with total size of 4 bytes void*operator new(unsigned) + 0x36 void foo() + 0x5e <tdata.C:5> 2: 3: void foo() 4: { 5:=> int *j = new int; 6: } 7: 8: int main() main()+0x1a <tdata.C:10> 9: { 10:=> foo(); 11: discover_report_all_leaks(); 12: 13: foo(); _start() + ********************************************************** ******** discover_report_unreported_leaks() Report ******** 1 allocation at 1 location left on the heap with a total size of 4 bytes LEAK 1: 1 allocation with total size of 4 bytes void*operator new(unsigned) + 0x36 void foo() + 0x5e <tdata.C:5> 2: 3: void foo() 4: { 5:=> int *j = new int; 6: } 7: 8:int main() main() + 0x24 <tdata.C:13> 10: foo(); 11: discover_report_all_leaks(); 12: 13:=> foo(); 14: discover_report_unreported_leaks(); 15: 16:return 0; _start() + 0x71 ********************************************************** ***************** Discover Memory Report ***************** 2 allocations at 2 locations left on the heap with a total size of 8 bytes LEAK 1: 1 allocation with total size of 4 bytes void*operator new(unsigned) + 0x36 void foo() + 0x5e <tdata.C:5> 2: 3: void foo() 4: { 5:=> int *j = new int; 6: } 7: 8: int main() main() + 0x1a <tdata.C:10> 7: 8: int main() 9: { 10:=> foo(); 11: discover_report_all_leaks(); 12: 13: foo(); _start() + 0x71 LEAK 2: 1 allocation with total size of 4 bytes void*operator new(unsigned) + 0x36 void foo() + 0x5e <tdata.C:5> 2: 3: void foo() 4: { 5:=> int *j = new int; 6: } 7: 8: int main() main() + 0x24 <tdata.C:13> 10: foo(); 11: discover_report_all_leaks(); 12: 13:=> foo(); 14: discover_report_unreported_leaks(); 15: 16: return 0; _start() + 0x71 DISCOVER SUMMARY: unique errors : 0 (0 total) unique warnings : 0 (0 total)
如果您有长期运行的程序或从不退出的服务器,则可以随时使用 dbx 调用这些 discover 函数,即使您未将调用放置在代码中也可以执行此操作。必须至少已使用 –l 选项以 discover 的轻量模式运行了该程序。请注意,dbx 可以附加到正在运行的程序。以下示例显示如何在长期运行的程序中查找泄漏
示例 1 在长期运行的程序中找到两处泄漏对于本示例,a.out 文件是长期运行的具有两个进程的程序,每个进程存在一处泄漏。为每个进程分配了一个进程 ID。
以下 rl 脚本包含用于指示程序报告尚未报告的内存泄漏的命令。
#!/bin/sh dbx - $1 > /dev/null 2> &1 << END call discover_report_unreported_leaks() exit END
一旦您具有程序和脚本,就可以使用 discover 并运行该程序。
% discover -l -w - a.out % a.out 8252: Parent allocation 64 8253: Child allocation 32
在单独的终端窗口中,可以对父进程运行脚本。
% rl 8252
程序针对父进程报告以下信息:
******** discover_report_unreported_leaks() Report ******** 1 allocation at 1 location left on the heap with a total size of 64 bytes LEAK 1: 1 allocation with total size of 64 bytes main() + 0x1e <xx.c:17> 14: 15: if (child > 0) { 16: 17:=> void *p = malloc(64); 18: printf("%jd: Parent allocation 64\n", (intmax_t)getpid()); 19: p = 0; 20: for (int j=0; j < 1000; j++) sleep(1); _start() + 0x66 **********************************************************
针对子进程再次运行脚本。
% rl 8253
程序针对子进程报告以下信息:
******** discover_report_unreported_leaks() Report ******** 1 allocation at 1 location left on the heap with a total size of 32 bytes LEAK 1: 1 allocation with total size of 32 bytes main() + 0x80 <xx.c:24> 21: } 22: 23: else { 24:=> void *p = malloc(32); 25: printf("%jd: Child allocation 32\n", (intmax_t)getpid()); 26: p = 0; 27: for (int j=0; j < 1000; j++) sleep(1); _start() + 0x66 **********************************************************
可以重复使用脚本查找任何新的泄漏。
您可以通过将 SUNW_DISCOVER_OPTIONS 环境变量设置为命令行选项 –a、–A、–b、–e、–E、–f、–F、–H、–l、–L、–m、–P、–S 和 –w 的列表来更改检测过的二进制文件的运行时行为。例如,如果您希望将报告的错误数更改为 50 并将报告中的堆栈深度限制为 3,则可以按以下方式设置环境变量:
–e 50 –s 3
缺省情况下,如果您使用 discover 检测的二进制文件在您运行该文件时派生,discover 会继续从父进程和子进程收集内存访问错误数据,这表示缺省行为是 both。例如,如果您希望 discover 跟随派生并从子进程收集内存访问数据,请将 SUNW_DISCOVER_FOLLOW_FORK_MODE 环境变量设置为:
–F child