美文网首页
python对象内存消耗浅析

python对象内存消耗浅析

作者: 高稚商de菌 | 来源:发表于2018-05-06 20:49 被阅读0次

    最近遇到一个问题,为了提高查找速率,将一个mysql表的内容加载到内存中,竟然消耗了远高于表大小的内存,导致内存耗尽。猜测是python对象占用的内存大。为了验证这个问题,做了一些测试。

    先介绍一个函数:sys.getsizeof可以返回在内存中占的大小,单位为byte。以字节(byte)为单位返回对象大小。
    以下是摘录:

    这个对象可以是任何类型的对象。 所以内置对象都能返回正确的结果 但不保证对第三方扩展有效,因为和具体实现相关。
    getsizeof() 调用对象的 __sizeof__ 方法, 如果对象由垃圾收集器管理, 则会加上额外的垃圾收集器开销。

    也就是说,getsizeof和__sizeof__的结果可能会有些差异。比如列表和字典类型,getsizeof结果会大于__sizeof__。

    说明一下,python结构占用内存大小和操作系统,尤其是操作系统位数高度相关。以下测试使用的操作系统为64位ubuntu系统。

    首先是布尔型型,可以看到布尔型占了24Byte。对于整型而言,可以看到普通整型为24Byte,长整型为28Byte。

    >>> b = False
    >>> print sys.getsizeof(b)
    24
    >>> import sys
    # int
    >>> i = 1
    >>> print sys.getsizeof(i)
    24
    >>> i = 1L
    >>> print sys.getsizeof(i)
    28
    

    字符串类型:空字符串占了37Byte,每多一个字符多1Byte。

    # string
    >>> s = ""
    >>> print sys.getsizeof(s)
    37
    >>> s = "a"
    >>> print sys.getsizeof(s)
    38
    >>> s = "ab"
    >>> print sys.getsizeof(s)
    39
    

    列表类型,空列表为72byte,每多一项元素,多8byte。无论这个元素是本身占多少内存,都是多8Byte。因为,在list中,只是存放了这个元素的内存地址,在64位操作系统中,内存地址的大小为8Byte。元组类型也是也是类似的。

    # list
    >>> l = []
    >>> print sys.getsizeof(l)
    72
    >>> l = [1,2,3]
    >>> print sys.getsizeof(l)
    96
    >>> l = [1,2,[1,2,3]]
    >>> print sys.getsizeof(l)
    96
    

    字典类型,空字典占用280Byte,而有有了元素的列表依然是280?! 这是因为字典本质上是hash数组。初始化一个字典的时候,会分配一个长度为8的数组。随着数组中的被使用(或者曾经被使用过,这被称为dummpy slot)的槽位的总数超过数组长度的2/3,则需调整数组的长度,即rehash。数组长度调整后的长度不小于活动槽数量的 4 倍,而当活动槽的数量非常大(大于50000)时,调整后长度应不小于活动槽数量的2倍。也就是说,只有rehash,调用sys.getsizeof的结果才会有变化。

    # dict
    >>> d = {}
    >>> print sys.getsizeof(d)
    280
    >>> d["a"] = "a"
    >>> print sys.getsizeof(d)
    280
    >>> d["b"] = "b"
    >>> print sys.getsizeof(d)
    280
    

    python对象中,除了对象的值以外,还要包括比如引用计数,对象类型,引用地址等值,同时也会涉及到对象本身的实现,比如字典的哈希表。所以使用到的内存大小是远远高于对象本身的大小的。这在今后的编程中需要警惕。

    相关文章

      网友评论

          本文标题:python对象内存消耗浅析

          本文链接:https://www.haomeiwen.com/subject/eeaurftx.html