Python读取文件后删除数据,内存占用无法恢复至初始状态的原因及API服务内存增长疑问
嗨,我完全理解你看到内存没回到初始值时的困惑——按直觉删了数据内存就该降回去才对,其实这种情况是Python内存管理的正常表现,咱们一步步拆解原因,再说说API服务的内存顾虑:
一、为什么删除数据后内存没法回到初始值?
Python的内存池机制
Python自带专属的内存分配器(比如小对象用pymalloc),它不会把释放的内存立刻还给操作系统。当你del data并调用gc.collect()后,这些内存会被Python存在自己的内存池里,留着给后续的内存分配复用。而你用rss统计的是进程实际占用的物理内存,操作系统还没收回这部分内存,所以数值不会立刻降到初始状态。JSON解析的额外残留开销
json.loads()处理大文件时,除了生成data对象,还会产生一些临时对象、字符串缓存(比如Python的字符串intern机制会缓存重复的短字符串,避免重复创建),或者解释器内部的临时结构。虽然del data删掉了核心对象,但这些零散的小内存块可能没法被彻底回收,或者gc清理起来有延迟,也会让内存有少量残留。
另外,你原来的代码里没显式删除c这个读取文件得到的大字符串——它也占了不少内存!虽然gc最终可能会处理,但显式del c能更快释放这部分空间。
- RSS统计的局限性
初始的11.875MB是程序刚启动的状态:这时候很多模块(比如psutil、json)还没完全加载,解释器内部的缓存也没建立。当你运行过一次读取解析后,模块已经加载完成,解释器的内部状态也变了,这些开销是永久的(只要程序在运行),所以哪怕回收了所有业务数据,内存也不可能回到刚启动时的水平。
二、API服务会不会一直无限增长内存?
放心,只要你的代码没有内存泄漏(比如意外保留了对大对象的引用,比如把处理完的data存在全局变量、闭包、或者某个没清理的缓存里),内存不会无限增长。
Python的内存池会复用之前释放的内存:当新的请求进来时,会优先从内存池里分配空间,而不是向操作系统申请新内存。只有当请求需要的内存超过了当前内存池的大小,rss才会临时增长,但后续的请求会复用之前释放的空间,内存最终会稳定在一个合理的范围。
你可以做个简单测试:把读取-删除的逻辑循环跑个5-10次,看看内存是不是稳定在某个值,而不是每次循环都涨。比如修改你的代码:
import psutil import os import json import gc def main(): pid = os.getpid() print(f"pid of program is {pid}") # 初始内存 memory_info = psutil.Process(pid).memory_info() print(f'initial memory: {memory_info.rss / (1024 * 1024):.2f} MB') # 循环多次测试 for i in range(5): with open('temp.json', 'r') as file: c = file.read() data = json.loads(c) memory_info = psutil.Process(pid).memory_info() print(f'after read {i+1}: {memory_info.rss / (1024 * 1024):.2f} MB') # 显式删除所有大对象 del data del c gc.collect() memory_info = psutil.Process(pid).memory_info() print(f'after delete {i+1}: {memory_info.rss / (1024 * 1024):.2f} MB') print("---") if __name__ == "__main__": main()
运行后你会发现,第一次循环后内存会涨,但后面几次循环的内存波动会很小,最终稳定在一个值,不会持续上升。
总结一下
- 内存没回到初始值是Python内存管理的正常设计,不是内存泄漏;
- 正常的API服务只要没有泄漏,内存会稳定在一个区间,不会无限增长;
- 如果实在担心,可以用
tracemalloc模块跟踪内存分配,排查有没有意外的引用保留。
备注:内容来源于stack exchange,提问作者Saksham Ghimire




