pyhton打包exe执行内存不断增长问题

关于python程序使用pyinstaller打包exe, 执行过程中内存不断增长问题
  1. 我使用的python版本为3.7.9 打包使用 pyinstaller
  2. 最开始 使用的是 objgraph 模块,会显示变量的类型总数的增长数量的显示, 但是只显示变量 类型,不显示变量属性,不容易直接观看
# !/usr/bin/python
# -*- coding: UTF-8 -*-

if __name__ == '__main__':
    # 复制代码
    import objgraph as objgraph
    objgraph.show_growth()
    import MySQLdb
    # 打开数据库连接
    db = MySQLdb.connect("localhost", "root", "root", '', 3306)
    print(type(db))
    # 使用cursor()方法获取操作游标
    cursor = db.cursor()
    print(type(cursor))
    # 使用execute方法执行SQL语句
    cursor.execute("SELECT VERSION()")
    # 使用 fetchone() 方法获取一条数据库。
    data = cursor.fetchone()
    print(type(data))
    print("Database version : %s " % data)
    # 关闭数据库连接
    db.close()
    # del db
    # del cursor
    # del data
    import objgraph as objgraph
    objgraph.show_growth()

结果显示如下, 效果不是很明显

function                       7600     +7600
dict                           3999     +3999
tuple                          3219     +3219
wrapper_descriptor             2012     +2012
weakref                        1814     +1814
list                           1746     +1746
method_descriptor              1474     +1474
builtin_function_or_method     1394     +1394
getset_descriptor              1353     +1353
type                           1028     +1028
<class 'MySQLdb.connections.Connection'>
<class 'MySQLdb.cursors.Cursor'>
<class 'tuple'>
Database version : 8.0.25 
function               7673       +73
method_descriptor      1543       +69
dict                   4054       +55
set                     535       +37
tuple                  3255       +36
FuncCodeInfo            281       +33
wrapper_descriptor     2041       +29
weakref                1839       +25
type                   1050       +22
getset_descriptor      1370       +17
  1. 我找到了memory_profiler这个第三方库,它可以帮助我们分析记录Python脚本中,执行到每一行时,内存的消耗及波动变化情况。
    memory_profiler的使用方法超级简单,使用pip install memory_profiler完成安装后,只需要从memory_profiler导入profile并作为要分析的目标函数的装饰器即可
#!/usr/bin/python
# -*- coding:utf-8 -*-

from matplotlib import pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.neighbors import KNeighborsClassifier
from memory_profiler import profile


@profile
def iris_test():
    scores = []
    ks = []
    iris = datasets.load_iris()
    feature = iris['data']
    target = iris['target']
    # 拆分出训练集和测试集
    x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.2, random_state=2020)
    print(x_train.shape)
    print(x_test.shape)
    print(y_train.shape)
    print(y_test.shape)
    # 5.实例化模型对象
    # n_neighbors == k-在knn中k的取值不同会直接导致分类结果的不同,n_neighbors就是K值。
    # ·模型的超参数:如果模型参数有不同的取值且不同的取值会模型的分类或者预测会产生直系的影响。
    knn = KNeighborsClassifier(n_neighbors=5)
    print(knn)
    # 6.使用训练集数据训练模型
    # X:训练集的特征数据、特征数据的维度必须是二维。
    # y:训练集的标签数据
    knn = knn.fit(x_train, y_train)
    # 7.测试模型:使用测试数据
    # predict表示使用训练好的模型实现分类或者预测
    y_pred = knn.predict(x_test)
    # 模型基于测试数据返回的分类结果
    y_true = y_test
    # 测试集真实的分类结果
    print('模型的分类结果:', y_pred)
    print('
<think>好的,用户问的是Python程序打包内存占用较多,而且运行过程中内存一直在缓慢上升的问题。我需要逐步分析可能的原因和解决方法。首先,用户提到的是打包后的程序,这可能涉及到打包工具(如PyInstaller)的影响,但更多时候问题出在代码本身或者资源管理上。 首先,内存缓慢上升通常意味着存在内存泄漏。Python有自动垃圾回收机制,但如果存在循环引用或者某些对象被意外保留,可能会导致内存无法释放。需要检查是否有全局变量或缓存未及时清理,或者使用了第三方库存在泄漏。 然后,考虑打包工具的影响。有些打包工具可能会增加内存的开销,尤其是在导入大量模块或资源时。比如,PyInstaller的单文件执行包在启动时会解压到临时目录,可能会占用更多内存,但运行时的内存增长应该还是代码的问题。 接下来,用户可能需要检查代码中的常见问题。比如,是否有大列表或字典不断增长,是否在循环中未及时释放资源,或者是否有文件句柄、数据库连接未关闭。此外,使用C扩展的库(如NumPy)如果处理不当,也可能导致内存问题。 工具推荐方面,可以用memory_profiler来逐行分析内存使用,或者objgraph来查看对象引用关系。对于打包后的程序,可能需要将这些工具集成到代码中进行调试。 另外,注意多线程或异步编程中的问题,比如协程未正确结束,或者线程未释放资源。还有,某些第三方库可能存在已知的内存泄漏问题,需要检查版本和更新情况。 最后,建议用户分步骤排查:先用工具定位内存增长的位置,检查代码中的资源管理,确保及时释放不再需要的对象,使用生成器代替大列表,分块处理数据等。如果是打包工具的问题,可以尝试不同的打包配置,或者分文件打包减少初始内存占用。 总结起来,问题可能出在代码的内存泄漏、资源未释放,或者打包配置不当。需要结合工具分析和代码审查来解决。</think>Python程序打包内存占用较高且持续上升的问题,通常与代码逻辑、资源管理或打包方式有关。以下是逐步排查和优化的方向: --- ### **一、内存上升的常见原因** #### 1. **内存泄漏(Memory Leak)** - **现象**:对象未被垃圾回收(GC),导致内存累积。 - **可能原因**: - 全局变量或缓存未清理(如大字典/列表无限增长)。 - 第三方库的缓存机制(如`matplotlib`的`pyplot`默认缓存图形对象)。 - 未正确释放外部资源(如文件句柄、数据库连接、网络连接)。 - 循环引用(尤其是涉及自定义类或复杂数据结构时)。 #### 2. **打包工具的影响** - **单文件打包**:PyInstaller等工具生成单文件时,启动时会解压到临时目录,可能占用额外内存。 - **依赖项加载**:打包时包含未使用的库(如`pandas`+`numpy`会加载大量C扩展)。 #### 3. **数据处理方式** - 大文件一次性读入内存(如`pd.read_csv()`未分块处理)。 - 无限循环中累积数据(如实时数据采集未设置清理策略)。 --- ### **二、定位内存问题的工具** #### 1. **内存分析工具** - `memory_profiler`:逐行分析内存占用。 ```python # 安装后使用 from memory_profiler import profile @profile def your_function(): # 目标代码 ``` - `tracemalloc`(Python内置):跟踪内存分配。 ```python import tracemalloc tracemalloc.start() # ...运行代码... snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') for stat in top_stats[:10]: print(stat) ``` #### 2. **可视化工具** - `objgraph`:生成对象引用关系图。 ```python import objgraph objgraph.show_most_common_types(limit=10) # 显示最多实例的类型 ``` --- ### **三、优化策略** #### 1. **修复内存泄漏** - 及时释放全局变量或缓存: ```python big_list.clear() # 替代 big_list = [] ``` - 使用弱引用(`weakref`)管理缓存。 - 显式关闭资源: ```python with open('file.txt', 'r') as f: # 自动关闭 # 操作文件 ``` #### 2. **优化数据处理** - 分块读取大文件: ```python import pandas as pd chunk_size = 10000 for chunk in pd.read_csv('large.csv', chunksize=chunk_size): process(chunk) ``` - 使用生成器(`yield`)替代列表缓存。 #### 3. **打包配置优化** - 排除未使用的库: ```bash pyinstaller --exclude-module=unused_lib your_script.py ``` - 使用`--onedir`代替`--onefile`:减少启动时的解压内存开销。 --- ### **四、验证效果** 1. 运行优化后的程序,持续监控内存: - **任务管理器**(Windows)或`htop`(Linux)。 - Python内置模块`psutil`: ```python import psutil process = psutil.Process() print(process.memory_info().rss) # 获取内存占用 ``` 2. 对比优化前后的内存曲线,确认是否趋于稳定。 --- ### **五、常见陷阱** - **第三方库的内存问题**:如`numpy`/`tensorflow`的预分配内存池可能显示较高占用,但不一定泄漏。 - **多线程/异步编程**:协程未正确退出或线程未释放资源。 --- 通过以上步骤,你可以逐步定位内存占用高的代码段并针对性优化。如果问题仍存在,建议提供最小可复现代码片段进一步分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值