结局python3.6下调试程序的内存溢出问题
问题描述:
我分批读取的一批训练样本,原则上来说在读取下一个批次的数据时,上一个批次不应该依然占据内存。但实际运行时还是出现了内存溢出的情况,所以针对此问题单独进行分析。
分析python3.6的内存释放机制
理论部分
网上找到的python内存释放基本都是类似于智能指针,若出现变量对应的指针计数为0则清楚其内存。具体可以参考:PYTHON内存释放详解
实验一: python3.6使用numpy验证内存释放
计算机当前内存使用 1.8GiB
运行
a = np.arange(10**8 ,dtype = np.int32)
10 * 8 * 4 = 0.4GiB,当前计算机内存 2.2GiB [正常]
a = 1
由于array数据指针丢失,其内存会释放,当前计算机内存1.8GiB[正常]
命令 | 理论内存消耗GiB | 实际内存消耗GiB |
---|---|---|
a = np.arange(10**8 ,dtype = np.int32) | 0.4 | 0.4 |
a.astype(np.int64) | 0.8 | 1.2 |
del a | 0 | 0.8 |
分析:在做astype时直接重新开辟了一块新的空间即使没有完全的指向,即使当做完del a 释放变量a后,此空间依然存在。
初始化了一块内存,即使未赋给变量此空间依然会被占用
实验二:将内存申请释放置函数中观察其释放
>>> def test():
... a = np.arange(10**8 ,dtype = np.int32)
... return a
>>> a = test()
>>> b = test()
>>> del a
>>> del b
内存使用变化 0.4 - > 0.8 -> 0.4 -> 0[正常]
>>> def test():
... a = np.arange(10**8 ,dtype = np.int32)
... a.astype(np.int64)
... return a
...
>>> a = test()
>>> b = test()
>>> del a
>>> del b
0.4-> 0.8 ->0.4 ->0 正常
分析:若给定新开辟的空间一个作用域,超过其作用域仍未被引用则会自动释放。
解决办法
强制垃圾回收
import gc
gc.collect()
续一个由于joblib引起的问题
def load_small_imdb(cur_ban):
cur_ban = (cur_ban + 1) % ban_num
fid = open(os.path.join(base_path,"smaill.imdb"),'rb')
print("read...")
train_data = pickle.load(fid)
fid.close()
print("finist...")
random.shuffle(train_data)
print("shuffle")
tmp_list = np.array(train_data)
a = tmp_list[:,0].tolist()
b = np.copy(a) #如果不进行copy会出现pickle的实际未释放的情况
share_rate = np.copy(tmp_list[:,1])
return b,share_rate,cur_ban
注意这里使用了copy,之所以使用copy是因为如果不拷贝,其array中的数据会依赖于pickle开启的空间,导致空间申请的过大。