内存统计
简介
用于统计driver运行时内存占用情况的工具。
当程序有内存泄漏产生时, mem_snapshot 方法仅统计不同handle下相对大小的改变,部分内存泄漏点仍难以找到和排查。本工具通过记录pdb中代码位置信息与内存申请指针的对应关系统计内存占用情况。统计内存占用的单位为字节,可生成日志文件,并行解析,获取以100ms为间隔的局部最大内存占用情况。
目前内存统计有两种形式, MemRecordType.LOG_RECORD MemRecordType.MEM_RECORD。 MEM_RECORD状态下内存统计工具仅在内存中存储当前driver的内存申请情况,而LOG_RECORD则会将所有历史申请数据保存在日志中。内存统计工具保存信息所占用空间不是由 gs 内存分配器所分配,其不会影响 mem_state 或 get_mem_report 结果。
需要注意的是,由于gs的内存申请极为频繁且统计工具需要保存内存申请位置与所申请空间指针的对应关系,开启内存统计工具后内存占用较大且运行速度明显减慢。
开启内存统计
开启内存统计后,会在driver内存管理器的申请处记录内存指针对应的申请位置及申请大小,在释放处减 少所释放内存指针对应申请位置的已申请大小。 一般情况下调用 set_enable_mem_profiler(MemRecordType.MEM_RECORD)开启 driver内部内存记录。并在内存泄露前后通过 ’get_mem_report() 查看当前申请未释放的内存信息即可定位内存泄露具体的申请位置。
system.core.set_enable_mem_profiler [native|static]
- bool set_enable_mem_profiler(int enable_type = 4)
- Enable internal memory record and get_mem_report, default : MemRecordType.MEM_RECORD
MemRecordType.CLOSED - close internal memory record
MemRecordType.LOG_RECORD - record memory info in log files and hash map
MemRecordType.LOG_FAST - record memory info in log files and array
MemRecordType.MEM_RECORD - record memory info only in hash map
MemRecordType.MEM_FAST - record memory info only in array
开启模式的划分:
- 以 "RECORD" 结尾的模式通过 hash 映射进行内存申请记录,一般来说其占用内存相对 "FAST" 模式更小,但hash映射有额外的性能消耗,同时hash表扩张时需要进行rehash同样有一定性能消耗。
- 以 "FAST" 结尾的模式会直接申请 1/4 page-alloc 大小的内存,用于存储所有可能的内存申请记录,空间消耗相对 "RECORD" 更大,但由于不需要 hash 和 rehash, 速度相对 "RECORD" 模式会快很多。
- 以 "LOG" 开头的模式相对以 "MEM" 开头的模式,会额外将所有内存申请记录写入driver 根路径下的本地日志文件中,且记录带有以100ms为间隔的时间戳。通过调用函数 mem_profiler.start_mem_log_profiler() 进行日志文件解析后,可以通过 mem_profiler.get_all_time_size() 查看内存数量随运行时间的变化情况。
具体的模式选择策略:
- 大部分情况下通过 MemRecordType.MEM_RECORD 模式启动 mem_record 后,在可能泄露的逻辑前后分别调用 get_mem_report() 进行对比即可拿到泄露的具体内存申请位置。
- 若内存申请较为频繁,以 MemRecordType.MEM_RECORD 模式启动后程序运行速度很慢,且机器有额外 1/4 page-alloc 内存的情况下,请以 带有 "FAST" 结尾的模式启动 mem_record。
- 若内存泄露问题复现后没有足够的时间窗口调用 get_mem_report 或者需排查长时间偶现的内存异常增长之后又恢复正常的情况,则可以选择带有 "LOG"开头的模式。将 "LOG" 模式下生成的以 memlog 开头的日志文件复制至driver根目录后即可解析, 详情见下文内存日志的使用。
简单的使用样例:
import gs.mem_profiler;
set_enable_mem_profiler(MemRecordType.MEM_RECORD);
array test_arr = [];
for(int i = 0; i < 10000; i++)
{
test_arr.push_back(get_system_info());// Internal mem_profiler will record the memory alloc place
}
map report = mem_profiler.get_mem_report();
write(report);
结果如下:
{ /* sizeof() == 2 */
"total_size" : 79850464,
"mem_report" : [ /* sizeof() == 11 */
"/test/test.gs line:6 size:79558144",
"G:\gs_master\master\gs\std\include\std_template\simple_vector.h line:251 size:259424",
"G:\gs_master\master\gs\std\include\std_template\simple_vector.h line:353 size:32768",
"G:\gs_master\master\gs\std\include\std_template\simple_vector.h line:132 size:32",
"/gs/mem_profiler.gs line:1109 size:32",
"/gs/mem_profiler.gs line:1107 size:32",
"/test/test.gs line:3 size:32",
"G:\gs_master\master\gs\mts\cmm_gc_gray_page.h line:59 size:0",
"G:\gs_master\master\gs\std\include\std_template\simple_list.h line:478 size:0",
"G:\gs_master\master\gs\std\src\std_template\simple_string.cpp line:405 size:0",
"G:\gs_master\master\gs\mts\cmm_gc_gray_page.h line:287 size:0",
],
}