具有相同字符的兩個Python字符串,a == b, 可以共享內存,id(a)== id(b), 或者可能在內存中兩次,id(a)!= id(b)。 嘗試Python何時爲相同的字符串分配新內存?
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內存2種串(或任何程序):
- Ustrings,在唯一的字符串的Ucache:這些節省內存,並做出= = b快,如果兩者都在Ucache中
- Ostrings,其他可能會被存儲多次。
intern(astring)
將astring放在Ucache(Alex +1)中; 除了我們什麼都不知道Python如何將Ostrings移到Ucache - 「ab」之後「a」+「b」是如何進入的? (「文件中的字符串」沒有意義 - 沒有辦法知道。)
簡而言之,Ucaches(可能有幾個)仍然不明朗。
一個歷史註腳: SPITBOL 獨特的所有字符串約。 1970年
我的答案中有什麼有價值的東西,你不認爲是你的?如果不是,我會刪除我的答案。如果有的話,你想編輯它到你的和*然後*我會刪除我的答案? – 2010-01-23 17:54:23
+1提到'實習生'。我完全忘記了這個功能的存在。在\ n「.join(names).split()]中使用'joinsplit = [intern(n)'來完成這項工作,並將我的MacBook上的內存使用量從4,374,528降低到3,190,783。 – 2010-01-23 18:20:28
@John,我認爲有兩個觀點(我從一個「內幕人士的角度來看」,你是一位經驗豐富的程序員,對Python沒有特別的「內幕人士的觀點」)是非常有價值的 - 不確定是否有最佳的方式來獲得同一個「三角測量」在一個單一的答案! – 2010-01-23 18:36:33