在工作中出现了一个未曾注意的问题:python的内存泄露问题,直接说问题和解决方式:
我遇到的问题出现内存泄露主要是因为:使用c类型申请的变量数组造成的泄露,因为申请(ctype.c_int*len)() 这类的数组的时候,没有手动清除,导致在程序结束的时候,没有自动回收,导致内存不断的增加。
- python内存管理机制:
- 根据变量的引用计数,引用计数变为0,在结束的时候,垃圾回收机制,会回收;
- 标记清除:如果两个对象的引用计数都是1,两个对象是循环引用的,虽然引用计数表现为非0,但是实际上有效的引用计数为0,这两个变量都需要清除;
- 分代回收:垃圾回收分为0,1,2代;这个就是有的变量存活时间比较长,这种变量往往不能及时回收;这种就需要手动清楚;
- 调优的手段:
- 避免循环引用
- 手动垃圾回收
- 调高垃圾回收阈值(没有试验,前两个都用了。自认为系统的设置一般不动,毕竟不是专业的运维的。)
- 内存的问题使用的方式:
- heap():在python3中引入guppy3,from guppy import hpy 然后打印出栈中内存的使用情况:print(hpy().heap())
- import objgraph,显示内存中变量的增长情况使用objgraph.show_growth()
- memory_profiler:在函数的前边添加@profile 显示内存的变化,我这里没有用这个。
- 使用tracemalloc,查看没有释放内存的变量和位置,这是我主要使用的方式,
- 使用tracker,先查看是否有内存泄露,
- from pympler import tracker,summary,muppy
- memory_tracer = tracker.SummaryTracker()
- 程序流程
- 查看是否有内存泄露:memory_tracer.print_diff()
- 使用tracemalloc 查看泄露的位置
- import tracemalloc
- tracemalloc.start() 运行的程序
- snapshot1 = tracemalloc.take_snapshot()
- top_stats = snapshot1.statistics('lineno') #定位变量的名字和位置
- for stat in top_stats[:limit]: #limit:自己定义个数,要显示的个数
- print(stat)
- 根据这个可以找到没有释放掉位置,找到变量,在使用完变量后,要手动销毁,del +变量的名字
- 在结束后使用gc.collect(),释放掉需要释放的变量。