【问题标题】:Python: size of strings in memoryPython:内存中字符串的大小
【发布时间】:2012-02-25 15:13:50
【问题描述】:

考虑以下代码:

arr = []
for (str, id, flag) in some_data:
    arr.append((str, id, flag))

假设输入字符串平均长度为 2 个字符,最大为 5 个字符,并且 some_data 具有 100 万个元素。 这种结构的内存要求是多少?

可能是因为字符串浪费了很多内存吗?如果是这样,我该如何避免呢?

【问题讨论】:

    标签: python arrays memory-management


    【解决方案1】:

    在这种情况下,因为字符串很短,而且有很多,你可以通过在字符串上使用intern 来节省相当多的内存。假设字符串中只有小写字母,也就是 26 * 26 = 676 个可能的字符串,所以这个列表中肯定有很多重复; intern 将确保这些重复不会产生唯一的对象,而是都引用同一个基础对象。

    有可能 Python 已经实习了短字符串;但是查看许多不同的来源,这似乎高度依赖于实现。所以在这种情况下调用intern可能的方法; YMMV。

    详细说明为什么这很可能节省内存,请考虑以下几点:

    >>> sys.getsizeof('')
    40
    >>> sys.getsizeof('a')
    41
    >>> sys.getsizeof('ab')
    42
    >>> sys.getsizeof('abc')
    43
    

    将单个字符添加到字符串中只会在字符串本身的大小上增加一个字节,但每个字符串本身会占用 40 个字节。

    【讨论】:

    • 现在我了解到 python 通常非常消耗内存。正如您正确指出的那样,字符串的长度不是问题,而是对象的最小大小。发现一个简单的 int 的大小是 24 字节(在 64 位系统上),我有点震惊。很高兴知道...
    【解决方案2】:

    如果您的字符串很短,很可能会有大量重复。 Python interning 会对其进行优化,使这些字符串只存储一次,并且引用使用多个 tiem,而不是多次存储字符串...

    这些字符串应该被自动保留。

    【讨论】:

    • 字符串字面量是内嵌的,但从其他来源创建的字符串不一定是内嵌的。每次从文件中读取内容时,您都不会希望调用 intern...
    【解决方案3】:

    在最近的 Python 3(64 位)版本中,字符串实例占用 49+ 字节。但也要记住,如果你使用非 ASCII 字符,内存使用量会增加更多:

    >>> sys.getsizeof('t')
    50
    >>> sys.getsizeof('я')
    76
    

    请注意,即使字符串中的一个字符不是 ASCII,所有其他字符也会占用更多空间(每个 2 或 4 个字节):

    >>> sys.getsizeof('t12345')
    55  # +5 bytes, compared to 't'
    >>> sys.getsizeof('я12345')
    86  # +10 bytes, compared to 'я'
    

    这与 Python 3.3 以来字符串的内部表示有关。详情请见PEP 393 -- Flexible String Representation

    一般来说,Python 在处理大量小对象时内存效率不是很高,而不仅仅是字符串。请参阅以下示例:

    >>> sys.getsizeof(1)
    28
    >>> sys.getsizeof(True)
    28
    >>> sys.getsizeof([])
    56
    >>> sys.getsizeof(dict())
    232
    >>> sys.getsizeof((1,1))
    56
    >>> sys.getsizeof([1,1])
    72
    

    内部化字符串可能会有所帮助,但请确保您没有太多唯一值,因为这可能弊大于利。

    很难说出如何优化您的具体情况,因为没有单一的通用解决方案。例如,如果您以某种方式将多个项目中的数据序列化到一个单字节缓冲区中,您可以节省大量内存,但这可能会使您的代码复杂化或过多地影响性能。在许多情况下,这不值得,但如果我处于真的需要优化内存使用的情况,我也会考虑用 Rust 之类的语言编写该部分(这不是太例如,很难通过PyO3 创建原生 Python 模块)。

    【讨论】:

      猜你喜欢
      • 2014-08-06
      • 2011-02-20
      • 1970-01-01
      • 2011-12-24
      • 2010-11-08
      • 2020-09-13
      • 2011-02-13
      • 2014-01-27
      • 1970-01-01
      相关资源
      最近更新 更多