当前位置: 首页 > 面试题库 >

Python何时为相同的字符串分配新的内存?

裴金鑫
2023-03-14
问题内容

两个具有相同字符的Python字符串a == b,可以共享内存id(a)== id(b),或者可以在内存中两次,id(a)!= id(b)。尝试

ab = "ab"
print id( ab ), id( "a"+"b" )

Python在这里认识到新创建的“ a” +“ b”与内存中已经存在的“ ab”相同-不错。

现在考虑一个由N个长的州名组成的列表[“ Arizona”,“ Alaska”,“ Alaska”,“ California”
…](在我的情况下为N〜500000)。
我看到50个不同的id()s⇒每个字符串“ Arizona” …仅存储一次,很好。
但是将列表写入磁盘,然后再次读回:“相同”列表现在具有N个不同的id(),增加了内存,请参见下文。

怎么了-谁能解释Python字符串内存分配?

""" when does Python allocate new memory for identical strings ?
    ab = "ab"
    print id( ab ), id( "a"+"b" )  # same !
    list of N names from 50 states: 50 ids, mem ~ 4N + 50S, each string once
    but list > file > mem again: N ids, mem ~ N * (4 + S)
"""

from __future__ import division
from collections import defaultdict
from copy import copy
import cPickle
import random
import sys

states = dict(
AL = "Alabama",
AK = "Alaska",
AZ = "Arizona",
AR = "Arkansas",
CA = "California",
CO = "Colorado",
CT = "Connecticut",
DE = "Delaware",
FL = "Florida",
GA = "Georgia",
)

def nid(alist):
    """ nr distinct ids """
    return "%d ids  %d pickle len" % (
        len( set( map( id, alist ))),
        len( cPickle.dumps( alist, 0 )))  # rough est ?
# cf http://stackoverflow.com/questions/2117255/python-deep-getsizeof-list-with-contents

N = 10000
exec( "\n".join( sys.argv[1:] ))  # var=val ...
random.seed(1)

    # big list of random names of states --
names = []
for j in xrange(N):
    name = copy( random.choice( states.values() ))
    names.append(name)
print "%d strings in mem:  %s" % (N, nid(names) )  # 10 ids, even with copy()

    # list to a file, back again -- each string is allocated anew
joinsplit = "\n".join(names).split()  # same as > file > mem again
assert joinsplit == names
print "%d strings from a file:  %s" % (N, nid(joinsplit) )

# 10000 strings in mem:  10 ids  42149 pickle len  
# 10000 strings from a file:  10000 ids  188080 pickle len
# Python 2.6.4 mac ppc

新增25jan:
Python内存(或任何程序的)中有两种字符串:

  • 唯一字符串的Ucache中的Ustring:可以节省内存,并且如果两个都在Ucache中,则可以使a == b快速
  • Ostrings,其他的,可以存储多次。

intern(astring)将字符串放入Ucache(Alex
+1);除此之外,我们对Python如何将Ostrings移到Ucache一无所知-在“ ab”之后,“ a” +“
b”是如何进入的?(“文件中的字符串”没有意义-无法知道。)
简而言之,Ucache(可能有几个)仍然模糊。

历史脚注: SPITBOL
统一所有字符串ca。1970年。


问题答案:

Python语言的每种 实现 都可以自由地在分配不可变对象(例如字符串)中进行权衡取舍-
制作一个新对象,或者找到一个现有的相等对象并使用一个以上引用,对于该语言而言,观点看法。当然,在实践中,现实世界中的实现会做出合理的折衷:在找到这样的对象时,再引用一个合适的现有对象既便宜又容易,如果要找到合适的现有对象(可能会可能不存在)看起来可能需要很长时间才能搜索到。

因此,例如,在一个函数中多次出现相同字符串文字(在我所知道的所有实现中)将使用“对同一对象的新引用”策略,因为在构建该函数的常量池时,它非常容易快捷避免重复;但是跨
单独的
功能执行此操作可能是一项非常耗时的任务,因此现实世界中的实现要么根本不执行此操作,要么仅在某些启发式确定的情况子集中做到这一点,而这些子集可以希望我们合理地权衡编译时间(通过搜索相同的现有常量而降低)与内存消耗(如果不断制作新的常量副本会增加内存消耗)。

我不知道Python的任何实现(或与此有关的其他具有常量字符串的语言,例如Java)在从文件中读取数据时会麻烦识别可能的重复项(以通过多个引用重用单个对象),
-这似乎不是一个有希望的折衷办法(在这里您要付出 运行时的 费用,而不是 编译
时的费用,所以这种折衷的吸引力就更小了)。当然,如果您知道(由于应用程序级别的考虑)这样的不可变对象很大并且很容易发生很多重复,则可以很容易地实现自己的“常量池”策略(实习生可以帮助您为字符串做这件事,但是不难为自己而作,例如具有不可变项的元组,巨大的长整数,



 类似资料:
  • 问题内容: 我有两个字符串,它们看起来都一样: 但是,检查相等性表明它们不是。 我还尝试从命令提示符中复制两个字符串,并将它们作为新变量粘贴回去,但是它们仍然不相等。我有80%的把握是因为它们的编码方式很怪异,插入了一些我看不见的奇数字符,但是使用type()都只是显示为字符串。 有什么办法可以看到“真实”字符串?任何帮助表示赞赏。 问题答案: 他们是不一样的; using显示了这两个值之间的差异

  • 问题内容: 通过搜索发现了类似的问题,但我是一位新的(糟糕的)程序员,无法理解答案。 我有一个.txt文件,其中包含多个字符串,以’-‘分隔。我使用拆分将一些字符串分成变量,其中两个相等,但是在if语句中它们不相等。 这将产生以下结果: 瑞典 瑞典 没有 在两个“ Sweden”字符串之前和之后都有一个空格,并且它们都用大写字母“ S”编写,但不相等吗?我在哪里搞砸了? 问题答案: 最后一个元素包

  • 问题内容: 拥有Java代码 该字符串将分配在相同的内存位置(或多倍): 是否多次启动同一程序(并行)执行? 可能的答案: 我目前是C#开发人员(尽管在上个千年中使用Java编程)。 我之所以问这个问题,是因为我相信.NET CLR和Java(JVM)之间是相同的,我希望得到.NET应用程序的答案(但由于经常遇到的“应用程序”池术语而引起疑问)。 答案是 字符串 实习生池由同一JVM或.NET C

  • 下面的代码安全吗?编写类似这样的代码可能很有诱惑力: 该映射仅用于字符串文本。 我认为这是完全合法的,似乎正在起作用,但是我从未见过保证在两个不同地方使用的文字指针是相同的。我无法设法让编译器为具有相同内容的文本生成两个单独的指针,所以我开始怀疑这个假设有多坚定。 我只关心相同内容的文字是否可以有不同的指针。或者更正式地说,上面的代码可以除外吗? 我知道有一种方法可以编写代码来确保它有效,我认为上

  • 问题内容: 我知道问题的标题不是很清楚,对此感到抱歉,不知道如何提出。我有一个非常基本的Java实现问题,我想着重于应用程序性能,但是它也涉及Java中的String创建模式。 我了解Java中字符串的不变性概念。我不确定的是,我在某处读到以下内容不会创建两个不同的String对象: 我想知道Java是怎么做到的?它实际上是否在程序存储器中寻找一个String值并检查其是否存在,如果不存在则创建一

  • 问题内容: 在下面的代码中: 为了确定从CloudFoundry接收JSON数据所需的数据类型,请测试上面的示例代码以了解vs 类型的内存分配。 类型变量的预期大小为1个字节x 4个ascii编码字母= 4个字节,但是大小显示为16个字节。 对于类型变量,GO将字符串作为字符串文字嵌入到可执行程序中。它将在运行时使用该函数将字符串文字转换为字节片。就像是… 类型变量的预期大小再次为1字节x 4 a