- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我是Python新手,只是想知道内存分配是如何工作的。事实证明,测量存储变量大小的一种方法是使用 sys.getsizeof(x) ,它将返回 x 占用的字节数内存中,对吗?以下是示例代码:
import struct
import sys
x = struct.pack('<L', 0xffffffff)
print(len(x))
print(sys.getsizeof(x))
给出:
4
37
我刚刚创建的变量x
是一个4字节的字符串,第一个问题就出现在这里。为什么分配给4字节字符串的内存是37
字节?是不是多余的空间太多了?
当我开始创建 2 * 4 字节字符串列表时,情况变得更加复杂。下面你会发现另外几行:
import struct
import sys
k = 2
rng = range(0, k)
x = [b''] * k
for i in rng:
x[i] = struct.pack('<L', 0xffffffff)
print(len(x))
print(len(x[0]))
print(sys.getsizeof(x))
print(sys.getsizeof(x[0]))
从中我得到:
2
4
80
37
另一个问题是,为什么当我在列表中存储两个 4 字节字符串时,分配给它们的内存总和不等于它们单独大小的总和?!即37 + 37 != 80
。这额外的 6 个字节有什么用?
让我们将k
放大到10000
,前面的代码给出:
10000
4
80064
37
将单独大小与整体大小进行比较时,差异显着增大:37 * 10000 = 370000 != 80064
。看起来列表中的每个项目现在都占用 80064/10000 = 8.0064
字节。听起来可行,但我仍然无法解决之前显示的冲突。
毕竟,我的主要问题是,当我将 k
提高到 0xffffffff
并期望获得大小为 ~ 8 * 0xffffffff = 34359738360 的列表时
我实际上遇到了MemoryError异常。有什么方法可以消除非关键内存空间,以便我的 8G DDR3 RAM 可以托管这个变量x
?
最佳答案
Why is the memory allocated to a 4-byte string is 37 bytes? Is not that too much extra space?
Python 中的所有对象在每个对象的基础上都有一定程度的“溢出”。请注意,对于 bytes
以及可能所有不可变的 stdlib 类型,此填充(此处为 33 字节)独立于对象的长度:
from sys import getsizeof as gso
print(gso(b'x'*1000) - gso(b''))
# 1000
请注意,这不与:
print(gso([b'x']*1000) - gso(b''))
# 8031
在前者中,您正在创建一个 1000 x 的 bytes
对象。
在后者中,您将创建一个 1000 字节对象的列表。重要的区别在于,在后者中,您 (a) 复制字节对象 1000 次,并合并列表容器的大小。 (差异的原因只是 ~8,000 而不是 ~34,000(即每个元素 8 个字节,而不是每个元素 34 个字节 (=sizeof(b'x')
))。)
让我们谈谈容器:
print(gso([b'x'*100,]) - gso([]))
这里我们打印一个元素列表(100 字节长的 byte
对象)和一个空列表的 getsizeof
之间的差异。我们有效地taring超出容器的大小。
我们可能期望这等于getsizeof(b'x' * 100)
。
事实并非如此。
print(gso([b'x'*100,]) - gso([]))
的结果是 8 个字节(在我的机器上),因为列表只包含引用/指向底层对象的指针,而这 8 个字节就是指向列表中单个元素的指针。
That is 37 + 37 != 80. What are those extra 6 bytes for?
让我们做同样的事情,通过减去容器的大小来查看净大小:
x = [b'\xff\xff\xff\xff', b'\xff\xff\xff\xff']
print(gso(x[0]) - gso(b'')) # 4
print(gso(x) - gso([])) # 16
在第一个例子中,返回的 4 与我提供的第一个示例中返回的 1000 一样,每个字节一个。 (len(x[0])
为 4)。
在第二个中,每个子列表引用有 8 个字节。它与这些子列表的内容无关:
N = 1000
x = [b'x'] * N
y = [b'xxxx'] * N
print(gso(x) == gso(y))
# True
但是虽然可变容器似乎没有固定的“slop”:
lst = []
for _ in range(100):
lst.append('-')
x = list(lst)
slop = gso(x) - (8 * len(x))
print({"len": len(x), "slop": slop})
输出:
{'len': 1, 'slop': 88}{'len': 2, 'slop': 88}{'len': 3, 'slop': 88}{'len': 4, 'slop': 88}{'len': 5, 'slop': 88}{'len': 6, 'slop': 88}{'len': 7, 'slop': 88}{'len': 8, 'slop': 96}{'len': 9, 'slop': 120}{'len': 10, 'slop': 120}{'len': 11, 'slop': 120}{'len': 12, 'slop': 120}{'len': 13, 'slop': 120}{'len': 14, 'slop': 120}{'len': 15, 'slop': 120}{'len': 16, 'slop': 128}{'len': 17, 'slop': 128}{'len': 18, 'slop': 128}{'len': 19, 'slop': 128}{'len': 20, 'slop': 128}{'len': 21, 'slop': 128}{'len': 22, 'slop': 128}{'len': 23, 'slop': 128}{'len': 24, 'slop': 136}...
...Immutable containers do:
lst = []
for _ in range(100):
lst.append('-')
x = tuple(lst)
slop = gso(x) - (8 * len(x))
print({"len": len(x), "slop": slop})
{'len': 1, 'slop': 48}{'len': 2, 'slop': 48}{'len': 3, 'slop': 48}{'len': 4, 'slop': 48}{'len': 5, 'slop': 48}{'len': 6, 'slop': 48}{'len': 7, 'slop': 48}{'len': 8, 'slop': 48}{'len': 9, 'slop': 48}{'len': 10, 'slop': 48}{'len': 11, 'slop': 48}{'len': 12, 'slop': 48}{'len': 13, 'slop': 48}{'len': 14, 'slop': 48}...
Is there any way to eliminate non-critical memory spaces so that my 8G DDR3 RAM can host this variable x?
First, recall that the sizeof a container will not reflect the entire amount of memory used by Python. The ~8 bytes per element is the size of the pointer, each of those elements will consume an additional 37 (or whatever) bytes (sans interning or similar optimization).
But the good news is that it's unlikely you probably don't need the entire list at the same time. If you're just building a list to iterate over, then generate it one element at a time, with a for loop or generator function.
Or generate it a chunk at a time, process it, and then continue, letting the garbage collector clean up the no-longer-used memory.
One other interesting thing to point out
N = 1000
x = [b'x' for _ in range(N)]
y = [b'x'] * N
print(x == y) # True
print(gso(x) == gso(y)) # False
(这可能是由于 y
的大小是先验已知的,而 x
的大小则未知且已调整大小随着它的成长)。
关于python - 如何在 8G DDR3 RAM 中托管大型列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53348835/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!