为何Pandas在Ubuntu上的内存占用远高于macOS?
Pandas/Numpy跨平台内存泄漏问题排查与解决
环境配置
- 操作系统:Linux Ubuntu 22.04、macOS Monterey 12.2.1
- Python版本:3.10
- 依赖库:Pandas 1.5.2、Numpy 1.23.5、Psutil 5.9.5(两端版本完全一致)
问题现象
在macOS开发的Python代码部署到Ubuntu服务器后,内存占用差异显著:Ubuntu端内存会快速耗尽并导致进程被终止。通过测试代码复现,确认Pandas相关操作存在内存泄漏,使用Memray分析定位到泄漏点在'dot at <__array_function__internals>'行,但无法进一步排查。
复现测试代码
import pandas as pd import numpy as np import psutil import sys import ctypes # 设置循环次数 n = 100000 memory_check = 0 memory_check_prev = 0 # 存储相关系数的列表 correlation_values = [] # 创建随机数据的DataFrame df = pd.DataFrame(np.random.rand(3600, 2), columns=['Column1', 'Column2']) # 循环执行相关计算 for _ in range(n): ### 相关系数计算 correlation = df['Column1'].corr(df['Column2']) ### 其他可测试操作(注释状态) # df['returns'] = df['Column1'].pct_change() # df2 = df.loc[200:500] # df2 = df.loc[str(200):str(500)] # 调用malloc_trim回收内存 if sys.platform.startswith('linux'): malloc_lib = ctypes.CDLL('/usr/lib/x86_64-linux-gnu/libc.so.6') else: malloc_lib = ctypes.CDLL('/Users/koen/libcustommalloc.dylib') malloc_lib.malloc_trim.argtypes = [ctypes.c_size_t] malloc_lib.malloc_trim.restype = None malloc_lib.malloc_trim(0) # 检查内存变化 memory_check = psutil.Process().memory_info().rss / 1000000000 if memory_check != memory_check_prev: print('New total memory load: ' + str(memory_check)) memory_check_prev = memory_check
Malloc_trim 环境准备
- Linux端:直接使用系统libc库路径
/usr/lib/x86_64-linux-gnu/libc.so.6 - macOS端:需编译自定义dylib文件,C代码如下:
#include <stdio.h> #include <stdlib.h> #include <malloc/malloc.h> void malloc_trim(size_t pad) { malloc_zone_t *zone = malloc_default_zone(); malloc_zone_pressure_relief(zone, pad); }
编译命令:
gcc -shared -o libcustommalloc.dylib -fPIC custommalloc.c
编译完成后修改Python代码中的对应路径。
解决方案与排查方向
- 升级依赖库版本
Pandas 1.5.2和Numpy 1.23.5存在已知的底层内存管理问题,建议升级到:
- Pandas 1.5.3+ 或 2.x 系列
- Numpy 1.24.x+
这些版本修复了多个内存泄漏相关的bug,尤其是涉及到dot运算和DataFrame操作的场景。
- 替换Pandas方法为原生Numpy实现
Pandas的corr方法封装了Numpy的计算逻辑,直接使用Numpy的np.corrcoef可以减少封装层的内存开销,避免潜在的泄漏:
# 替换原correlation计算行 correlation = np.corrcoef(df['Column1'].values, df['Column2'].values)[0, 1]
- 优化内存回收策略
- 减少
malloc_trim的调用频率:频繁调用会影响性能,可改为每N次循环调用一次(如每100次) - 主动触发Python垃圾回收:结合
gc模块在循环间隙回收内存
import gc # 在循环内添加 if _ % 100 == 0: gc.collect() if sys.platform.startswith('linux'): malloc_lib = ctypes.CDLL('/usr/lib/x86_64-linux-gnu/libc.so.6') malloc_lib.malloc_trim(0)
- 排查Numpy后端问题
Ubuntu默认的OpenBLAS后端可能存在内存泄漏,可尝试:
- 切换到MKL后端(通过
conda install numpy mkl安装) - 编译Numpy时启用内存分配优化选项
- 深入内存分析
- 使用Python内置的
tracemalloc追踪Python层面的内存分配:
import tracemalloc tracemalloc.start() # 执行测试代码后获取快照 snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') for stat in top_stats[:10]: print(stat)
- 使用Linux的
valgrind工具排查C层面泄漏(注意:会大幅降低程序运行速度):
valgrind --leak-check=full python your_script.py
内容的提问来源于stack exchange,提问作者Koen Smits
相关产品推荐
相关产品推荐

