设为首页 加入收藏

TOP

如何高效解决 C++内存问题,Apache Doris 实践之路|技术解析(一)
2023-07-23 13:29:21 】 浏览:95
Tags:何高效 解决 Apache Doris 解析

导读:Apache Doris 使用 C++ 语言实现了执行引擎,C++ 开发过程中,影响开发效率的一个重要因素是指针的使用,包括非法访问、泄露、强制类型转换等。本文将会通过对 Sanitizer 和 Core Dump 分析工具的介绍来为大家分享:如何快速定位 Apache Doris 中的 C++ 问题,帮助开发者提升开发效率并掌握更高效的开发技巧。

?作者|Apache Doris Committer杨勇强

Apache Doris 是一款高性能 MPP 分析型数据库,出于性能的考虑,Apache Doris 使用了 C++ 语言实现了执行引擎。在 C++ 开发过程中,影响开发效率的一个重要因素是指针的使用,包括非法访问、泄露、强制类型转换等。Google Sanitizer 是由 Google 设计的用于动态代码分析的工具,在 Apache Doris 开发过程中遭遇指针使用引起的内存问题时,正是因为有了 Sanitizer,使得问题解决效率可以得到数量级的提升。除此以外,当出现一些内存越界或非法访问的情况导致 BE 进程 Crash 时,Core Dump 文件是非常有效的定位和复现问题的途径,因此一款高效分析 CoreDump 的工具也会进一步帮助更加快捷定位问题。

本文将会通过对 Sanitizer 和 Core Dump 分析工具的介绍来为大家分享:如何快速定位 Apache Doris 中的 C++ 问题,帮助开发者提升开发效率并掌握更高效的开发技巧。

Sanitizer 介绍

定位 C++ 程序内存问题常用的工具有两个,Valgrind 和 Sanitizer。

二者的对比可以参考:https://developers.redhat.com/blog/2021/05/05/memory-error-checking-in-c-and-c-comparing-sanitizers-and-valgrind

其中 Valgrind 通过运行时软件翻译二进制指令的执行获取相关的信息,所以 Valgrind 会非常大幅度的降低程序性能,这就导致在一些大型项目比如 Apache Doris 使用 Valgrind 定位内存问题效率会很低。

而 Sanitizer 则是通过编译时插入代码来捕获相关的信息,性能下降幅度比 Valgrind 小很多,使得能够在单测以及其它测试环境默认使用 Saintizer。

Sanitizer 的算法可以参考:https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm

在 Apache Doris 中,我们通常使用 Sanirizer 来定位内存问题。LLVM 以及 GNU C++ 有多个 Sanitizer:

  • AddressSanitizer(ASan)可以发现内存错误问题,比如 use after free,heap buffer overflow,stack buffer overflow,global buffer overflow,use after return,use after scope,memory leak,super large memory allocation;
  • AddressSanitizerLeakSanitizer (LSan)可以发现内存泄露;
  • MemorySanitizer(MSan)可以发现未初始化的内存使用;
  • UndefinedBehaviorSanitizer (UBSan)可以发现未定义的行为,比如越界数组访问、数值溢出等;
  • ThreadSanitizer (TSan)可以发现线程的竞争行为;

其中 AddressSanitizer, AddressSanitizerLeakSanitizer 以及 UndefinedBehaviorSanitizer 对于解决指针相关的问题最为有效。

Sanitizer 不但能够发现错误,而且能够给出错误源头以及代码位置,这就使得问题的解决效率很高,通过一些例子来说明 Sanitizer 的易用程度。

可以参考此处使用 Sanitizer:https://github.com/apache/doris/blob/master/be/CMakeLists.txt

Sanitizer 和 Core Dump 配合定位问题非常高效,默认 Sanitizer 不生成 Core Dump 文件,可以使用如下环境变量生成 Core Dump文件,建议默认打开。

可以参考:https://github.com/apache/doris/blob/master/bin/start_be.sh

export ASAN_OPTIONS=symbolize=1:abort_on_error=1:disable_coredump=0:unmap_shadow_on_exit=1

使用如下环境变量让 UBSan 生成代码栈,默认不生成。

export UBSAN_OPTIONS=print_stacktrace=1

有时候需要显示指定 Symbolizer 二进制的位置,这样 Sanitizer 就能够直接生成可读的代码栈。

export ASAN_SYMBOLIZER_PATH=your path of llvm-symbolizer

Sanitizer 使用举例

Use after free

User after free 是指访问释放的内存,针对 use after free 错误,AddressSanitizer 能够报出使用释放地址的代码栈,地址分配的代码栈,地址释放的代码栈。比如:https://github.com/apache/doris/issues/9525中,使用释放地址的代码栈如下:

82849==ERROR: AddressSanitizer: heap-use-after-free on address 0x60300074c420 at pc 0x56510f61a4f0 bp 0x7f48079d89a0 sp 0x7f48079d8990
READ of size 1 at 0x60300074c420 thread T94 (MemTableFlushTh)
    #0 0x56510f61a4ef in doris::faststring::append(void const*, unsigned long) /mnt/ssd01/tjp/incubator-doris/be/src/util/faststring.h:120
// 更详细的代码栈请前往https://github.com/apache/doris/issues/9525查看

此地址初次分配的代码栈如下:

previously allocated by thread T94 (MemTableFlushTh) here:
    #0 0x56510e9b74b7 in __interceptor_malloc (/mnt/ssd01/tjp/regression_test/be/lib/palo_be+0x536a4b7)
    #1 0x56510ee77745 in Allocator<false, false>::alloc_no_track(unsigned long, unsigned long) /mnt/ssd01/tjp/incubator-doris/be/src/vec/common/allocator.h:223
    #2 0x56510ee685
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++面试八股文:如何在堆上和栈上.. 下一篇C++ Protobuf

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目