Apache Gluten内存泄漏排查:使用Valgrind定位原生代码问题的方法
Apache Gluten内存泄漏排查:使用Valgrind定位原生代码问题的方法
【免费下载链接】glutenGluten is a middle layer responsible for offloading JVM-based SQL engines' execution to native engines.项目地址: https://gitcode.com/GitHub_Trending/glu/gluten
Apache Gluten作为将JVM-based SQL引擎执行卸载到原生引擎的中间层,其内存管理对系统稳定性至关重要。原生代码内存泄漏可能导致Spark Executor因内存超限被杀死,本文将介绍如何使用Valgrind工具快速定位Gluten项目中的C++内存泄漏问题。
内存泄漏的常见表现与危害
在Gluten中,内存泄漏通常表现为:
- Spark Executor进程异常退出并提示内存超限
- 长时间运行任务后OffHeap内存持续增长
- 间歇性OOM错误且难以复现
特别是当原生内存不受Gluten管理时,传统Java内存分析工具无法捕获泄漏点,此时需要Valgrind等原生代码调试工具介入。
Valgrind工具准备与环境配置
安装Valgrind
在Ubuntu/Debian系统中通过apt直接安装:
apt install valgrind对于CentOS/RHEL系统:
yum install valgrind编译调试版本的Gluten
为获得准确的内存泄漏追踪信息,需要编译包含调试符号的Gluten原生代码:
# 编译Velox后端并启用测试和调试模式 gluten_home/dev/builddeps-veloxbe.sh --build_tests=ON --build_benchmarks=ON --build_type=Debug使用Valgrind检测内存泄漏的步骤
编写针对性的单元测试
根据docs/developers/NewToGluten.md建议,创建GoogleTest测试用例来隔离可能存在泄漏的代码路径。例如创建exec_backend_test测试可执行文件,专注测试 shuffle 或计算逻辑。
执行Valgrind内存检查
使用Valgrind的memcheck工具运行测试:
valgrind --leak-check=yes ./exec_backend_test关键参数说明:
--leak-check=yes:启用内存泄漏检测--show-reachable=yes:显示可达内存块(潜在泄漏)--track-origins=yes:追踪未初始化值的来源
分析Valgrind输出结果
Valgrind会生成详细的内存泄漏报告,包括:
- 泄漏内存总量和块数
- 每个泄漏点的调用栈
- 内存分配位置和大小
典型的泄漏报告类似:
==12345== LEAK SUMMARY: ==12345== definitely lost: 1,024 bytes in 4 blocks ==12345== indirectly lost: 4,096 bytes in 16 blocks ==12345== possibly lost: 0 bytes in 0 blocks ==12345== still reachable: 8,192 bytes in 32 blocks ==12345== suppressed: 0 bytes in 0 blocks结合内存分析工具定位问题
使用gperftools生成内存使用热力图
Gluten项目推荐使用gperftools辅助内存分析,通过以下命令生成内存使用GIF图:
pprof --show_bytes --gif --lib_prefix=/path/to/gluten_lib_prefix /usr/bin/java /path/to/gluten_heap_perf_XXX > result.gif图1:使用gperftools生成的内存分配热力图,可直观展示内存使用热点
分析内存分配文本报告
通过文本模式查看详细内存分配统计:
pprof --text --lib_prefix=/path/to/gluten_lib_prefix /usr/bin/java /path/to/gluten_heap_perf_XXX图2:内存分配统计报告,显示各函数内存分配占比
常见内存泄漏场景与解决方案
场景1:Arrow内存分配器泄漏
当看到类似以下日志时:
WARN ArrowBufferAllocators$ArrowBufferAllocatorManager: Detected leaked Arrow allocator [Default], size: 191...可启用Arrow内存调试:
-Darrow.memory.debug.allocator=true场景2:C++对象未正确释放
通过Valgrind定位到具体泄漏函数后,检查:
- 是否所有
new分配的对象都有对应的delete - 智能指针使用是否正确(如
std::unique_ptr/std::shared_ptr) - 资源获取即初始化(RAII)模式是否被遵守
场景3:JNI层内存管理不当
检查JNI接口实现:
jobject引用是否正确释放- 原生内存是否通过
NewGlobalRef/DeleteGlobalRef管理 - 避免在JNI回调中分配长期内存
验证修复效果
修复后应:
- 重新编译调试版本
- 再次运行Valgrind检查确认泄漏已解决
- 执行端到端测试确保功能正常
- 使用jemalloc生成内存快照进行对比:
jeprof --text --lib_prefix=/path/to/gluten_lib_prefix /usr/bin/java /path/to/gluten_heap_perf_XXX总结
使用Valgrind配合gperftools和jemalloc,能有效定位Gluten项目中的原生代码内存泄漏问题。关键步骤包括:
- 编译调试版本代码
- 编写针对性测试用例
- 分析Valgrind泄漏报告
- 结合内存分析工具可视化问题
- 验证修复效果
通过这套方法论,可以显著提升Gluten的内存管理质量,避免因内存泄漏导致的生产环境故障。完整的内存调试文档可参考docs/developers/ProfileMemoryOfGlutenWithVelox.md。
【免费下载链接】glutenGluten is a middle layer responsible for offloading JVM-based SQL engines' execution to native engines.项目地址: https://gitcode.com/GitHub_Trending/glu/gluten
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考