V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
yangyaofei
V2EX  ›  Python

关于 python 的 dict 的内存占用问题....

  •  
  •   yangyaofei ·
    yangyaofei · 2016-05-27 22:28:22 +08:00 · 4217 次点击
    这是一个创建于 3101 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近处理数据,有一个地方用的字典储存的,不知道为啥,有个地方的内存占用看不懂啊:

    这是第一种:

    31     83.4 MiB      0.0 MiB   @profile
    32                             def main():
    33                             	# data_count = taskResultDB.getResult(21, taskResultDB.resultType.FRQ_COUNT)
    34                             	# data_sum = taskResultDB.getResult(21, taskResultDB.resultType.FRQ_SUM)
    35                             	# data_tfidf = taskResultDB.getResult(21, taskResultDB.resultType.TFIDF)
    36                             	# data_tfidf_2 = taskResultDB.getResult(21, taskResultDB.resultType.TFIDF_2)
    37     83.4 MiB      0.0 MiB   	data = taskResultDB.getResult(21)
    38                             
    39                             	'''
    40                             	data_count = taskResultDB.tranDataToDict(
    41                             		data_count)[taskResultDB.resultType.FRQ_COUNT]
    42                             	data_sum = taskResultDB.tranDataToDict(
    43                             		data_sum)[taskResultDB.resultType.FRQ_SUM]
    44                             	data_tfidf = taskResultDB.tranDataToDict(
    45                             		data_tfidf)[taskResultDB.resultType.TFIDF]
    46                             	data_tfidf_2 = taskResultDB.tranDataToDict(
    47                             		data_tfidf_2)[taskResultDB.resultType.TFIDF_2]
    48                             	'''
    49   1778.2 MiB   1694.8 MiB   	datas = taskResultDB.tranDataToDict(data)
    50                             
    51                             	# wordDict = tranToWordDict(data_sum, data_count)
    52   1874.5 MiB     96.3 MiB   	wordDict = tranToWordDict_2(datas)
    53                             
    54                             	# data_count = None
    55                             	# data_sum = None
    56                             	# data_tfidf = None
    57                             	# data_tfidf_2 = None
    58   1850.5 MiB    -24.0 MiB   	datas = None
    59   1552.3 MiB   -298.2 MiB   	data = None
    60   1551.8 MiB     -0.5 MiB   	gc.collect()
    61   1551.8 MiB      0.0 MiB   	return wordDict
    

    第二种就是将注释去掉,注释掉现在的代码

    Line #    Mem usage    Increment   Line Contents
    ================================================
    31     83.4 MiB      0.0 MiB   @profile
    32                             def main():
    33     83.4 MiB      0.0 MiB   	data_count = taskResultDB.getResult(21, taskResultDB.resultType.FRQ_COUNT)
    34     83.4 MiB      0.0 MiB   	data_sum = taskResultDB.getResult(21, taskResultDB.resultType.FRQ_SUM)
    35     83.4 MiB      0.0 MiB   	data_tfidf = taskResultDB.getResult(21, taskResultDB.resultType.TFIDF)
    36     83.4 MiB      0.0 MiB   	data_tfidf_2 = taskResultDB.getResult(21, taskResultDB.resultType.TFIDF_2)
    37                             
    38     83.4 MiB      0.0 MiB   	data_count = taskResultDB.tranDataToDict(
    39    463.8 MiB    380.3 MiB   		data_count)[taskResultDB.resultType.FRQ_COUNT]
    40    463.8 MiB      0.0 MiB   	data_sum = taskResultDB.tranDataToDict(
    41    560.4 MiB     96.7 MiB   		data_sum)[taskResultDB.resultType.FRQ_SUM]
    42    560.4 MiB      0.0 MiB   	data_tfidf = taskResultDB.tranDataToDict(
    43    659.5 MiB     99.1 MiB   		data_tfidf)[taskResultDB.resultType.TFIDF]
    44    659.5 MiB      0.0 MiB   	data_tfidf_2 = taskResultDB.tranDataToDict(
    45    697.5 MiB     38.0 MiB   		data_tfidf_2)[taskResultDB.resultType.TFIDF_2]
    46                             
    47    713.1 MiB     15.6 MiB   	wordDict = tranToWordDict(data_sum, data_count)
    48                             
    49    712.6 MiB     -0.5 MiB   	data_count = None
    50    700.6 MiB    -12.0 MiB   	data_sum = None
    51    699.1 MiB     -1.5 MiB   	data_tfidf = None
    52    590.9 MiB   -108.2 MiB   	data_tfidf_2 = None
    53    546.9 MiB    -44.0 MiB   	gc.collect()
    54    546.9 MiB      0.0 MiB   	return wordDict
    

    data 是获取的一个 ORM 对象,获取数据的 数据是 4 部分,sun,count,tfidf,tfidf_2,转存出的 dict 的结构是:

    {
    	type:{
        		"word":	data
        		}
     }
     type 只有下面的四种...
    

    就是一个嵌套字典,只不过第二个是分开转换的. 可以理解为 data_count + data_sum + data_tfidf + data_tfidf_2 = data 但是根据信息能看出,输出的 data 字典占用的空间远远大于前几个的和,这是为什么呢

    哦,还有一个信息就是 count,sum,tfidf,tfidf_2 的内容除了 value 不一样以外,key 是一样的,和这个有关系么?

    python 用的我好想用 C++重写......几十万条瞬间一个 G 没了.....前段时间后台程序自己关了,连 log 里都没有信息,就像断点一样.....盯着俩消失才知道是内存消耗没了....

    第 1 条附言  ·  2016-05-28 09:59:37 +08:00
    原因找到了,是最后存入数据库的时候,一次性插入的太多了,改成一次插入 3000 个而不是全部(5w),就好了………
    第 2 条附言  ·  2016-05-28 10:04:18 +08:00
    上面的说错了…………
    7 条回复    2016-05-28 16:34:10 +08:00
    fcicq
        1
    fcicq  
       2016-05-28 00:04:48 +08:00   ❤️ 1
    dict 的动态类型支持不是无代价的所以本来就不省内存. key 压缩肯定也不会有. 用数据库的话说你建了四个表存了 4 份 key.
    yangtukun1412
        2
    yangtukun1412  
       2016-05-28 09:28:11 +08:00   ❤️ 1
    应该是 tranDataToDict() 方法内部使用了大量内存 + gc 的锅
    yangyaofei
        3
    yangyaofei  
    OP
       2016-05-28 09:58:02 +08:00 via Android
    @fcicq
    @yangtukun1412
    昨天一个原因一个原因找,发现不是字典的锅,是我用的数据库 orm peewee 的问题,我一次让他插入所有的表,估计是生成什么巨大的表达式了,我改成一次插入 3000 个表就好了………
    yangyaofei
        4
    yangyaofei  
    OP
       2016-05-28 10:02:44 +08:00 via Android
    @fcicq 数据库就一个,三个键一起做 key ,其实我奇怪的是同样的数据,一次性取出和分四次取出为何内存占用差这么多………

    @yangtukun1412 tran 函数没有占什么内存………
    yangyaofei
        5
    yangyaofei  
    OP
       2016-05-28 10:03:53 +08:00 via Android
    @fcicq
    @yangtukun1412 唉,糊涂了,这个问题不是数据库那部分………说错了
    yangyaofei
        6
    yangyaofei  
    OP
       2016-05-28 10:07:19 +08:00 via Android
    @yangtukun1412 我说错了, tran 函数确实占用了很大内存,但是是必要的。我说的是第一个 tran 是分开的而后面的是合并一起的,输出的数据是一样多的,但是后一个却占用比前一个高很多很多……
    yangtukun1412
        7
    yangtukun1412  
       2016-05-28 16:34:10 +08:00
    @yangyaofei 当使用了大量内存时, Python 的 gc 不会立即释放这部分内存,而是会尝试复用.

    最简单的测试方法, 你可以试一下函数中 range(1000000) 和 4 次 range(250000) 的内存消耗.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2675 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 11:55 · PVG 19:55 · LAX 03:55 · JFK 06:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.