想问一下,为什么这段代码内存占用不会降下来?

2016-03-22 20:42:19 +08:00
 yanyuechuixue

这是一部分代码,全部代码的话太长了。

    def main(rg1,rg2):
    global Abins
    Abins=[[[] for x in range(50)] for y in range(50)]
    for ra in range(rg1,rg2):
        for dec in range(180):
            print ra, dec
            if file_list[ra][dec] == []:
                continue
            else:
                print len(file_list[ra][dec])
                for b in file_list[ra][dec]:
                    for bins_ra in range(-4,5):
                        for bins_dec in range(-4,5):
                            for a in file_list[ra+bins_ra][dec+bins_dec]:
                                if a[4]<b[4]:
                                    calcute(str(a[0]),str(b[0]),a[3],b[3],a[1],b[1],a[2],b[2])
    print("start print")
    for i in range(FenShu):
        for j in range(FenShu):
            file_save=open('./Abins_'+str(rg1)+'_'+str(rg2)+'_'+str(i)+'_'+str(j), 'w')
            file_save.write(json.dumps(Abins[i][j]))
            file_save.close()
    del Abins
    gc.collect()


for ra in range(80,140):
    main(ra,ra+10)

这段代码的意思是,我每做一次 main 这个函数,都会往全局变量 Abins 数组中添加一些数据,由于全部做完之后这个数组会太大(远超过物理内存),所以每一次循环都输出一个文件。

但我的意图是输出完这个文件之后应该就释放了原来的 Abins 专用的内存了,不知道为什么执行的时候还是占用很多很多内存。 是做天文数据处理用的。 多谢!

3002 次点击
所在节点    Python
22 条回复
justfly
2016-03-22 20:48:57 +08:00
一个 python 进程内存的占用是这个进程运行中峰值的内存占用。

python 会把回收的内存放到自己的空闲链表中,并不是还给操作系统。
yanyuechuixue
2016-03-22 20:53:23 +08:00
@justfly 这样的话还是会跑着跑着内存占用 100%,然后跑不动了啊。。
有什么办法可以把内存占用降下来么?
yanyuechuixue
2016-03-22 20:54:24 +08:00
@justfly 就是,当内存占用百分之九十多的时候, CPU 占用率就只有百分之四、五, 而不是百分之百了……所以我认为是跑不动了。
justfly
2016-03-22 21:04:49 +08:00
函数里面的变量没必要 global 。 先看看你一次 main 占多少内存吧。把 for 去掉 只跑一次 main 然后用 sleep block 住看内存。
northisland
2016-03-22 21:07:02 +08:00
del Abins
这句放在 2 重循环外边了吧~~
读完所有文件再释放?
yanyuechuixue
2016-03-22 21:12:26 +08:00
@justfly 因为如果不 global 的话,在这个函数调用的另一个子函数就没法往 Abins 里填充元素……
yanyuechuixue
2016-03-22 21:19:37 +08:00
@northisland 嗯,执行完 main()之后再释放,下一次执行 main()再创建。
dreampuf
2016-03-22 21:24:20 +08:00
CPython 不会将内存释放给操作系统。 GC 只会将对象回收到 runtime 的 free list 中,以备再用。
解决方案简单粗暴就用子进程进行数据处理,然后将结果传递给父进程。
yanyuechuixue
2016-03-22 21:29:32 +08:00
@dreampuf 好的,谢谢,我试一下。
麻烦问一下,如果传递一个很大的数组的话,会不会速度会很慢?
dreampuf
2016-03-22 21:34:33 +08:00
如何传递?跨进程 /线程,还是同上下文只是函数调用?
建议 Google 一下,这些都是书本上的知识了
cphilo
2016-03-22 21:36:25 +08:00
考虑使用类似 xrange 这种迭代器
cphilo
2016-03-22 21:38:17 +08:00
应该是生成器,不是迭代器, v2 不能删除评论
sujin190
2016-03-22 21:42:28 +08:00
@dreampuf free list 不是有长度限制的么?超过了依然会释放的,不过会有整数缓存,字符串缓存什么的,如果你从 i 循环到数百万,内存占用数百 M 是正常的
mko0okmko0
2016-03-22 22:15:50 +08:00
PYPY 能好一点吗?我不知道等楼下回答.

我个人会推荐换用 JAVA 或其他语言来解决脚本语言的性能或是回收问题.
我帮你找的方法:
http://f.dataguru.cn/thread-296696-1-1.html

个人觉得 C#(mono)很棒(有 SIMD 加速),JAVA 次之(有 SSE/AVX 加速但要加参数)
dreampuf
2016-03-22 22:30:25 +08:00
sujin190
2016-03-23 13:21:21 +08:00
@dreampuf 是的,一般不开启,但看这个逻辑似乎是每次最小分配 16*256KB 字节,再分成 256KB 大小的每块,再在每块上分配对象需要的内存,但一块上所有对象都被释放的话,该块还是会被释放的
dreampuf
2016-03-23 18:19:32 +08:00
@sujin190 哪段代码?
sujin190
2016-03-23 20:41:06 +08:00
@dreampuf https://github.com/python/cpython/blob/master/Objects/obmalloc.c#L1598
而且内存限制也不是说不能超过这个内存,而是当内存超过这个值之后直接由 c 的 malloc 直接来分配,所以如果你有引用没有释放,内存依然还是会占用很高的
billgreen1
2016-03-24 00:10:51 +08:00
强烈建议你重构代码,六个 for 循环,我从来没见到过这么多的循环嵌套的。
yanyuechuixue
2016-03-25 20:14:47 +08:00
@billgreen1 我也没见过……这个已经没办法的事情了……这是我能想到的最节约时间数据结构决定的……
是把整个天空分成 180*360 个格子,每个里面放了好多个数组,对每个数组都要与周围的 64 个格子里的其他数组进行运算,这个运算包含两个循环………………

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/265564

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX