use*_*646 606 python memory memory-management object sizeof
在C中,我们可以找到的大小int,char等我想知道如何获得物体的大小就像一个字符串,整数,等在Python.
我使用的XML文件包含指定值大小的大小字段.我必须解析这个XML并进行编码.当我想更改特定字段的值时,我将检查该值的大小字段.在这里,我想比较一下我输入的新值是否与XML中的值相同.我需要检查新值的大小.在字符串的情况下,我可以说它的长度.但是在int,float等的情况下我很困惑.
nos*_*klo 592
只需使用模块中定义的sys.getsizeof函数即可sys.
sys.getsizeof(object[, default]):以字节为单位返回对象的大小.对象可以是任何类型的对象.所有内置对象都将返回正确的结果,但这不一定适用于第三方扩展,因为它是特定于实现的.
该
default参数允许定义一个值,如果对象类型没有提供检索大小的方法并将导致a,将返回该值TypeError.
getsizeof__sizeof__如果对象由垃圾收集器管理,则调用该对象的 方法并添加额外的垃圾收集器开销.
用法示例,在python 3.0中:
>>> import sys
>>> x = 2
>>> sys.getsizeof(x)
24
>>> sys.getsizeof(sys.getsizeof)
32
>>> sys.getsizeof('this')
38
>>> sys.getsizeof('this also')
48
Run Code Online (Sandbox Code Playgroud)
如果你在python <2.6但没有,sys.getsizeof你可以使用这个扩展模块.从来没有用过它.
Aar*_*all 308
如何在Python中确定对象的大小?
答案"只使用sys.getsizeof"并不是一个完整的答案.
这个问题的答案并不直接内置对象的工作,但它并没有占到什么这些对象可能包含,具体是什么类型,比如元组,列表类型的字典,并设置包含.它们可以包含彼此的实例,以及数字,字符串和其他对象.
使用来自Anaconda发行版的64位Python 3.6,使用sys.getsizeof,我确定了以下对象的最小大小,并注意set和dicts预分配空间,因此空的不会再次增长,直到设定量(可能因语言的实现而有所不同):
Python 3:
Empty
Bytes type scaling notes
28 int +4 bytes about every 30 powers of 2
37 bytes +1 byte per additional byte
49 str +1-4 per additional character (depending on max width)
48 tuple +8 per additional item
64 list +8 for each additional
224 set 5th increases to 736; 21nd, 2272; 85th, 8416; 341, 32992
240 dict 6th increases to 368; 22nd, 1184; 43rd, 2280; 86th, 4704; 171st, 9320
136 func def does not include default args and other attrs
1056 class def no slots
56 class inst has a __dict__ attr, same scaling as dict above
888 class def with slots
16 __slots__ seems to store in mutable tuple-like structure
first slot grows to 48, and so on.
Run Code Online (Sandbox Code Playgroud)
你怎么解释这个?好吧,你有一套10件物品.如果每个项目每个100字节,整个数据结构有多大?该集合本身就是736,因为它的大小为736字节.然后添加项目的大小,总共1736个字节
函数和类定义的一些注意事项:
注意每个类定义都有__dict__类attrs 的代理(48字节)结构.每个槽property在类定义中都有一个描述符(如a ).
Slotted实例在其第一个元素上以48个字节开始,每个额外增加8个.只有空的开槽对象有16个字节,而没有数据的实例几乎没有意义.
此外,每个函数定义都有代码对象,可能是文档字符串,以及其他可能的属性,甚至是__dict__.
Python 2.7分析,用guppy.hpy和确认sys.getsizeof:
Bytes type empty + scaling notes
24 int NA
28 long NA
37 str + 1 byte per additional character
52 unicode + 4 bytes per additional character
56 tuple + 8 bytes per additional item
72 list + 32 for first, 8 for each additional
232 set sixth item increases to 744; 22nd, 2280; 86th, 8424
280 dict sixth item increases to 1048; 22nd, 3352; 86th, 12568 *
120 func def does not include default args and other attrs
64 class inst has a __dict__ attr, same scaling as dict above
16 __slots__ class with slots has no dict, seems to store in
mutable tuple-like structure.
904 class def has a proxy __dict__ structure for class attrs
104 old class makes sense, less stuff, has real dict though.
Run Code Online (Sandbox Code Playgroud)
请注意,字典(但不是集合)在Python 3.6中得到了更紧凑的表示
我认为每个附加项目的8个字节在64位机器上很有意义.这8个字节指向包含项目所在的内存中的位置.如果我没记错的话,4字节是Python 2中unicode的固定宽度,但在Python 3中,str变成宽度等于字符最大宽度的unicode.
(有关插槽的更多信息,请参阅此答案)
为了覆盖大多数这些类型,我编写了这个递归函数来尝试估计大多数Python对象的大小,包括大多数内置函数,集合模块中的类型和自定义类型(插槽和其他):
import sys
from types import ModuleType, FunctionType
from gc import get_referents
# Custom objects know their class.
# Function objects seem to know way too much, including modules.
# Exclude modules as well.
BLACKLIST = type, ModuleType, FunctionType
def getsize(obj):
"""sum size of object & members."""
if isinstance(obj, BLACKLIST):
raise TypeError('getsize() does not take argument of type: '+ str(type(obj)))
seen_ids = set()
size = 0
objects = [obj]
while objects:
need_referents = []
for obj in objects:
if not isinstance(obj, BLACKLIST) and id(obj) not in seen_ids:
seen_ids.add(id(obj))
size += sys.getsizeof(obj)
need_referents.append(obj)
objects = get_referents(*need_referents)
return size
Run Code Online (Sandbox Code Playgroud)
而且我很随便地测试它(我应该对它进行单元测试):
import sys
from numbers import Number
from collections import Set, Mapping, deque
try: # Python 2
zero_depth_bases = (basestring, Number, xrange, bytearray)
iteritems = 'iteritems'
except NameError: # Python 3
zero_depth_bases = (str, bytes, Number, range, bytearray)
iteritems = 'items'
def getsize(obj_0):
"""Recursively iterate to sum size of object & members."""
_seen_ids = set()
def inner(obj):
obj_id = id(obj)
if obj_id in _seen_ids:
return 0
_seen_ids.add(obj_id)
size = sys.getsizeof(obj)
if isinstance(obj, zero_depth_bases):
pass # bypass remaining control flow and return
elif isinstance(obj, (tuple, list, Set, deque)):
size += sum(inner(i) for i in obj)
elif isinstance(obj, Mapping) or hasattr(obj, iteritems):
size += sum(inner(k) + inner(v) for k, v in getattr(obj, iteritems)())
# Check for custom object instances - may subclass above too
if hasattr(obj, '__dict__'):
size += inner(vars(obj))
if hasattr(obj, '__slots__'): # can have __slots__ with __dict__
size += sum(inner(getattr(obj, s)) for s in obj.__slots__ if hasattr(obj, s))
return size
return inner(obj_0)
Run Code Online (Sandbox Code Playgroud)
它有点打破了类定义和函数定义,因为我没有追求它们的所有属性,但由于它们应该只在内存中存在一次,因此它们的大小确实无关紧要.
ser*_*inc 80
该Pympler封装的asizeof模块可以做到这一点.
使用方法如下:
from pympler import asizeof
asizeof.asizeof(my_object)
Run Code Online (Sandbox Code Playgroud)
sys.getsizeof与之不同,它适用于您自己创建的对象.它甚至适用于numpy.
>>> asizeof.asizeof(tuple('bcd'))
200
>>> asizeof.asizeof({'foo': 'bar', 'baz': 'bar'})
400
>>> asizeof.asizeof({})
280
>>> asizeof.asizeof({'foo':'bar'})
360
>>> asizeof.asizeof('foo')
40
>>> asizeof.asizeof(Bar())
352
>>> asizeof.asizeof(Bar().__dict__)
280
>>> A = rand(10)
>>> B = rand(10000)
>>> asizeof.asizeof(A)
176
>>> asizeof.asizeof(B)
80096
Run Code Online (Sandbox Code Playgroud)
正如提到的,
如果你需要有关实时数据的其他观点,那就是Pympler's
module
muppy用于在线监视Python应用程序,模块Class Tracker提供所选Python对象生命周期的离线分析.
Mik*_*war 79
对于numpy数组,getsizeof不起作用 - 对我来说它总是因为某些原因返回40:
from pylab import *
from sys import getsizeof
A = rand(10)
B = rand(10000)
Run Code Online (Sandbox Code Playgroud)
然后(在ipython中):
In [64]: getsizeof(A)
Out[64]: 40
In [65]: getsizeof(B)
Out[65]: 40
Run Code Online (Sandbox Code Playgroud)
但幸运的是:
In [66]: A.nbytes
Out[66]: 80
In [67]: B.nbytes
Out[67]: 80000
Run Code Online (Sandbox Code Playgroud)
Arc*_*ast 39
您可以序列化对象以导出与对象大小密切相关的度量:
import pickle
## let o be the object whose size you want to measure
size_estimate = len(pickle.dumps(o))
Run Code Online (Sandbox Code Playgroud)
如果您想测量无法腌制的对象(例如,因为 lambda 表达式) dill 或 cloudpickle 可以是一个解决方案。
Mar*_*ski 19
如果您不想包含链接(嵌套)对象的大小,请使用sys.getsizeof()。
但是,如果您想计算嵌套在列表、字典、集合、元组中的子对象 - 通常这就是您要查找的 - 使用递归deep sizeof()函数,如下所示:
import sys
def sizeof(obj):
size = sys.getsizeof(obj)
if isinstance(obj, dict): return size + sum(map(sizeof, obj.keys())) + sum(map(sizeof, obj.values()))
if isinstance(obj, (list, tuple, set, frozenset)): return size + sum(map(sizeof, obj))
return size
Run Code Online (Sandbox Code Playgroud)
您还可以在漂亮的工具箱中找到此函数,以及许多其他有用的单行代码:
https://github.com/mwojnars/nifty/blob/master/util.py
Von*_*onC 11
Raymond Hettinger 在此宣布sys.getsizeof,Python 3.8(2019年第一季度)将更改的某些结果:
在64位版本中,Python容器要小8字节。
tuple () 48 -> 40
list [] 64 ->56
set() 224 -> 216
dict {} 240 -> 232
Run Code Online (Sandbox Code Playgroud)
这是在问题33597和Inada Naoki(methane)围绕Compact PyGC_Head和PR 7043开展的工作之后
这个想法将PyGC_Head的大小减少到两个单词。
目前,PyGC_Head包含三个词;
gc_prev,gc_next和gc_refcnt。
gc_refcnt收集时用于尝试删除。gc_prev用于跟踪和取消跟踪。因此,如果我们可以避免在尝试删除时进行跟踪/取消跟踪,
gc_prev并且gc_refcnt可以共享相同的内存空间。
已
Py_ssize_t从中删除一名成员PyGC_Head。
所有GC跟踪的对象(例如,元组,列表,字典)的大小都减少了4或8个字节。
小智 10
我自己多次遇到这个问题,我写了一个小函数(灵感来自@ aaron-hall的答案)和测试,它做了我原本希望sys.getsizeof做的事情:
https://github.com/bosswissam/pysize
如果你对背景故事感兴趣的话,就在这里
编辑:附上以下代码以便于参考.要查看最新代码,请查看github链接.
import sys
def get_size(obj, seen=None):
"""Recursively finds size of objects"""
size = sys.getsizeof(obj)
if seen is None:
seen = set()
obj_id = id(obj)
if obj_id in seen:
return 0
# Important mark as seen *before* entering recursion to gracefully handle
# self-referential objects
seen.add(obj_id)
if isinstance(obj, dict):
size += sum([get_size(v, seen) for v in obj.values()])
size += sum([get_size(k, seen) for k in obj.keys()])
elif hasattr(obj, '__dict__'):
size += get_size(obj.__dict__, seen)
elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):
size += sum([get_size(i, seen) for i in obj])
return size
Run Code Online (Sandbox Code Playgroud)
这是我根据以前对所有变量列表大小的答案编写的快速脚本
for i in dir():
print (i, sys.getsizeof(eval(i)) )
Run Code Online (Sandbox Code Playgroud)
使用以下函数获取 python 对象的实际大小:
import sys
import gc
def actualsize(input_obj):
memory_size = 0
ids = set()
objects = [input_obj]
while objects:
new = []
for obj in objects:
if id(obj) not in ids:
ids.add(id(obj))
memory_size += sys.getsizeof(obj)
new.append(obj)
objects = gc.get_referents(*new)
return memory_size
actualsize([1, 2, [3, 4, 5, 1]])
Run Code Online (Sandbox Code Playgroud)
参考:https://towardsdatascience.com/the-strange-size-of-python-objects-in-memory-ce87bdfbb97f
如果您不需要对象的确切大小,但粗略地知道它有多大,一种快速(但肮脏)的方法是让程序运行,长时间休眠,并检查内存使用情况(例如:Mac 的活动监视器)通过这个特定的 python 进程。当您尝试在 python 进程中查找单个大对象的大小时,这将非常有效。例如,我最近想检查一个新数据结构的内存使用情况,并与Python的集合数据结构进行比较。首先,我将元素(一本大型公共领域书籍中的单词)写入一个集合,然后检查进程的大小,然后对其他数据结构执行相同的操作。我发现带有集合的 Python 进程占用的内存是新数据结构的两倍。同样,您无法准确地说进程使用的内存等于对象的大小。随着对象的大小变大,这种情况会变得很接近,因为与您尝试监视的对象的大小相比,进程其余部分消耗的内存变得可以忽略不计。
| 归档时间: |
|
| 查看次数: |
526195 次 |
| 最近记录: |