使用Asan定位内存泄漏问题
更新时间: 2026/04/17
在Gitcode上查看源码Asan是一种内存错误检测工具,可以帮助我们定位内存泄漏问题。本文以devmon组件为例,介绍如何使用Asan工具定位内存泄漏问题
Asan简介
关于Asan工具,可以查看ASAN使用教程进行初步了解
使用Asan定位内存泄漏问题流程
以devmon为例(devmon示例),使用Asan的流程为:加上Asan相关编译选项、打包Asan相关的库、修改systemd配置,通过log_path指定Asan日志输出位置,其他组件也可以参考做类似修改集成Asan。下面分步骤进行介绍
加上Asan相关编译选项
可以参考devmon示例中conanfile.py添加的代码,进行添加
python
# 如果启用了 ASan,添加编译和链接选项
# if self.options.get_safe("asan", False):
print("Enable ASan flags for Meson build")
# 将 ASan 标志分开添加,避免 Meson 将它们当作单个参数
asan_compile_flags = [
"-fsanitize=address",
"-fsanitize-recover=address,all",
"-fno-omit-frame-pointer",
"-fno-stack-protector",
"-O1"
]
for flag in asan_compile_flags:
tc.extra_cflags.append(flag)
tc.extra_cxxflags.append(flag)
tc.extra_ldflags.append("-fsanitize=address")
# 设置 ASan 相关环境变量
if self.settings.arch == "armv8":
# 交叉编译环境,设置 ASan 库路径
toolchain_libdir = "/opt/hcc_arm64le/aarch64-target-linux-gnu/lib64"
if os.path.exists(toolchain_libdir):
tc.extra_ldflags.append(f"-Wl,-rpath-link,{toolchain_libdir}")打包Asan相关的库
可以参考devmon示例中conanfile.py的_package_asan_libs方法的修改,进行添加
def _package_asan_libs(self):
"""打包 AddressSanitizer 运行时库"""
import subprocess
print("Packaging AddressSanitizer runtime libraries...")
# 确定目标库目录
if self.settings.arch == "armv8" or self.settings.arch == "x86_64":
target_libdir = os.path.join(self.package_folder, "usr/lib64")
else:
target_libdir = os.path.join(self.package_folder, "usr/lib")
os.makedirs(target_libdir, exist_ok=True)
# 根据架构查找 ASan 库
asan_lib_paths = []
if self.settings.arch == "armv8":
# 交叉编译环境
toolchain_libdir = "/opt/hcc_arm64le/aarch64-target-linux-gnu/lib64"
if os.path.exists(toolchain_libdir):
# 查找 libasan.so*
for file in os.listdir(toolchain_libdir):
if file.startswith("libasan.so"):
asan_lib_paths.append(os.path.join(toolchain_libdir, file))
elif self.settings.arch == "x86_64":
# 本地编译环境
# 尝试通过 gcc 查找 libasan 路径
try:
result = subprocess.run(
["gcc", "-print-file-name=libasan.so"],
capture_output=True,
text=True,
timeout=10
)
if result.returncode == 0 and result.stdout.strip():
libasan_path = result.stdout.strip()
if os.path.exists(libasan_path):
# 获取目录并查找所有相关文件
libasan_dir = os.path.dirname(libasan_path)
for file in os.listdir(libasan_dir):
if file.startswith("libasan.so"):
asan_lib_paths.append(os.path.join(libasan_dir, file))
except Exception as e:
print(f"Warning: Failed to find libasan: {e}")
# 复制 ASan 库到包中
if asan_lib_paths:
for lib_path in asan_lib_paths:
if os.path.isfile(lib_path):
print(f" Copying {lib_path} to {target_libdir}")
copy(self, os.path.basename(lib_path),
src=os.path.dirname(lib_path),
dst=target_libdir)
elif os.path.islink(lib_path):
# 处理符号链接
link_target = os.readlink(lib_path)
link_name = os.path.basename(lib_path)
target_link = os.path.join(target_libdir, link_name)
if not os.path.exists(target_link):
os.symlink(link_target, target_link)
print(f" Created symlink {target_link} -> {link_target}")
print(f"Successfully packaged {len(asan_lib_paths)} ASan library files")
else:
print("Warning: No ASan libraries found to package")修改systemd配置,通过log_path指定Asan日志输出位置
可以参考devmon示例中devmon.service中进行的修改,进行添加
shell
Environment="ASAN_OPTIONS=abort_on_error=1:detect_leaks=1:verbosity=1:log_path=/data/asan.log"
Environment="LD_PRELOAD=/usr/lib64/libasan.so.4"