python 字典和类对象内存占用对比

__slots__适用于需要构建数百万以上众多对象,且内存容量较为紧张,同时实例的属性简单、固定且不用动态增加的场景

1、先看python中的简单对象int、float、字符串占用的内存,以及由这些类型构成的list所占用的内存

a = 1
print('整数1占用的内存为:', a.__sizeof__(), 'byte')  # 整数1占用的内存为: 28 byte
print('变量a的地址为:', id(a), '\n')  # 变量a的地址为: 139851337872608

b = 1
print('变量b的地址为:', id(b))  # 变量b的地址为: 139851337872608
print('为何id(a) = id(b)?', '\n')  # 为何id(a) = id(b)?

m = 0.01
print('浮点数0.01占用的内存为:', m.__sizeof__(), 'byte')  # 浮点数0.01占用的内存为: 24 byte
s = 'python 内存占用'
print('字符串占用的内存:', s.__sizeof__(), 'byte', '\n')  # 字符串占用的内存: 96 byte

list_item = [a, b, m, s]
print('列表占用的内存:', list_item.__sizeof__(), 'byte', '\n')  # 列表占用的内存: 72 byte
# 为何由整数、浮点数、字符串构成的列表所占用的内存,小于这些元素占用内存的总和?

s = 'python 内存占用 增加字符串的长度'
print('新的字符串内容占用的内存:', s.__sizeof__(), 'byte', '\n')  # 新的字符串内容占用的内存: 114 byte

list_item = [a, b, m, s]
print('列表占用的内存:', list_item.__sizeof__(), 'byte', '\n')  # 列表占用的内存: 72 byte
# 为何列表中的字符串占用的内存增加了,但列表的占用内存不变?

        python的sys模块中的getsizeof()、以及内置方法__sizeof__()对于python中的常规对象如int、float、string,能够正确的获取其占用的内存大小,但对于list、dict等,只会计算该对象的“指针”所占的空间,并不会把所指向的内容的内存大小也计算在内

    对此,官方文档给出了一种途径,即定义一个函数,通过递归的寻找容器中的所有引用并计算其内存占用,加总后返回即可,并且也给出了定义函数的源码,源码如下:

from __future__ import print_function
from sys import getsizeof, stderr
from itertools import chain
from collections import deque

try:
    from reprlib import repr
except ImportError:
    pass


def total_size(o, handlers={}, verbose=False):
    """ Returns the approximate memory footprint an object and all of its contents.
    Automatically finds the contents of the following builtin containers and
    their subclasses:  tuple, list, deque, dict, set and frozenset.
    To search other containers, add handlers to iterate over their contents:
        handlers = {SomeContainerClass: iter,
                    OtherContainerClass: OtherContainerClass.get_elements}
    """
    dict_handler = lambda d: chain.from_iterable(d.items())
    all_handlers = {tuple: iter,
                    list: iter,
                    deque: iter,
                    dict: dict_handler,
                    set: iter,
                    frozenset: iter,
                    }
    all_handlers.update(handlers)  # user handlers take precedence
    seen = set()  # track which object id's have already been seen
    default_size = getsizeof(0)  # estimate sizeof object without __sizeof__

    def sizeof(o):
        if id(o) in seen:  # do not double count the same object
            return 0
        seen.add(id(o))
        s = getsizeof(o, default_size)

        if verbose:
            print(s, type(o), repr(o), file=stderr)

        for typ, handler in all_handlers.items():
            if isinstance(o, typ):
                s += sum(map(sizeof, handler(o)))
                break
        return s

    return sizeof(o)
print('列表占用的内存:', total_size(list_item), 'byte', '\n')  # 列表占用的内存: 262 byte

2、对于dict对象,看一下dict_obj.__sizeof__()和字典实际占用的内存对比

p1_dict = {"name": 'zhao', "age": 60, "gender": 0, "decs": 'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm'}
print('p1_dict 内存占用对比:', p1_dict.__sizeof__(), 'byte vs', total_size(p1_dict), 'byte')
# p1_dict 内存占用对比: 216 byte vs 641 byte
p2_dict = {"name": 'sun', "age": 6, "gender": 1, "decs": 'mmmmmmmmmmmmmmmnnnnnmnmn'}
print('p2_dict 内存占用对比:', p2_dict.__sizeof__(), 'byte vs', total_size(p2_dict), 'byte')
# p2_dict 内存占用对比: 216 byte vs 634 byte
p3_dict = {"name": 'li', "age": 18, "gender": 0, "decs": 'nnn'}
print('p3_dict 内存占用对比:', p3_dict.__sizeof__(), 'byte vs', total_size(p3_dict), 'byte', '\n')
# p3_dict 内存占用对比: 216 byte vs 608 byte

3、对比字典与类对象的内存占用

class Person:
    def __init__(self, name, age, gender, decs):
        self.name = name
        self.age = age
        self.gender = gender
        self.decs = decs
p1_obj = Person('zhao', 60, 0, 'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm')
print('p1_obj 内存占用对比:', p1_obj.__sizeof__(), 'byte vs', total_size(p1_obj), 'byte')
# p1_obj 内存占用对比: 32 byte vs 56 byte
p2_obj = Person('sun', 6, 1, 'mmmmmmmmmmmmmmmnnnnnmnmn')
print('p2_obj 内存占用对比:', p2_obj.__sizeof__(), 'byte vs', total_size(p2_obj), 'byte')
# p2_obj 内存占用对比: 32 byte vs 56 byte
p3_obj = Person('li', 18, 0, 'nnn')
print('p3_obj 内存占用对比:', p3_obj.__sizeof__(), 'byte vs', total_size(p3_obj), 'byte', '\n')
# p3_obj 内存占用对比: 32 byte vs 56 byte

 可见,对于类实例对象,不管是__size__()方法,或者官方给的定义函数total_size()都无法准确算出类实例对象占用的实际内存

4、trancemalloc

    python标准库trancemalloc,可以统计内存使用情况

    python中使用字典能够提高查询效率,不过是用空间复杂度换取的时间复杂度

import tracemalloc


class Person:
    def __init__(self, name, age, gender, decs):
        self.name = name
        self.age = age
        self.gender = gender
        self.decs = decs


tracemalloc.start()  # start
p1_obj = Person('zhao', 60, 0, 'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm')
# p2_obj = Person('sun', 6, 1, 'mmmmmmmmmmmmmmmnnnnnmnmn')
# p3_obj = Person('li', 18, 0, 'nnn')
# end
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('filename')
for stat in top_stats[:4]:
    print(stat)
# /home/10333752@zte.intra/team/program_learning/learning/temp1.py:0: size=96 B, count=2, average=48 B
import tracemalloc


class PersonA:
    __slots__ = ['name', 'age', 'gender', 'decs']

    def __init__(self, name, age, gender, decs):
        self.name = name
        self.age = age
        self.gender = gender
        self.decs = decs


tracemalloc.start()  # start
p1_obj = PersonA('zhao', 60, 0, 'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm')
# p2_obj = PersonA('sun', 6, 1, 'mmmmmmmmmmmmmmmnnnnnmnmn')
# p3_obj = PersonA('li', 18, 0, 'nnn')
# end
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('filename')
for stat in top_stats[:4]:
    print(stat)
# /home/10333752@zte.intra/team/program_learning/learning/temp3.py:0: size=72 B, count=1, average=72 B

  __slots__的使用会阻止类实例产生__dict__来保存实例的属性

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值