如何估算一个Python对象的vs 查看对象内存占用用

Linux实际内存占用率算法,以及使用Python实现内存监控 - bisal的专栏 - CSDN博客
博客专家
Linux实际内存占用率算法,以及使用Python实现内存监控
技术之我见
这两天我们的一个核心系统,一套集群,逐台开始报警,内容是内存占用超阈值。按说这应该是一个非常紧急且需要立即处理的报警,但实际是不是这样,待我们拨云见日。以下为模拟实验,了解了下监控系统这条内存占用超阈值报警的计算方法,是用used/total*100%=0%=98%,即内存占用量超过了98%。网上学习了一番,其实这种计算方法不很准确,原因就是Linux的内存管理机制和Windows是不相同的,我理解Linux管理内存的特点,其中之一就是充分利用内存,网上这方面的资料,非常容易检索,我就不班门弄斧了。从MOS上看见了一些文章,直接或间接说明了这个问题,(1) Memory Not Being Released In Linux Top After The MDEX Engine Is Shut Down (文档 ID )问题是说为什么关闭了软件,从top中没有看见应用的释放内存?他的解释是,这是正常现象,top指令的memory部分展示的RAM是“缓存”的部分。这些缓存的部分表示磁盘中最近使用的数据且临时被存入RAM了。当停止一个应用程序的时候,不会“释放内存”,一旦重启应用,这些信息在缓存之中,可以提高性能。然而,如果关闭了应用程序许久,其他的进程需要这些内存,则可以无缝地使用这些内存。操作系统会回收尽可能少的数据段,分配给新的进程。(2) Summary Area in top output Shows Low Free Memory (文档 ID )Unix系统已经做了一些优化,可以充分利用所有可以使用的资源。不被代码或数据使用的内存资源会被OS用于各种用途。top指令输出中的汇总部分,未说明内核和用户进程的内存,单独看空闲的内存量非常低,并不能说明内存使用问题。未被进程使用的内存会被操作系统用来缓存一些最近访问过,而且不久的将来会被再次使用的数据,但若有一些更重要的进程需要这些内存,是可以非常轻松地释放出来。那么真实的内存占用率,应该如何计算?首先我们说下free输出中,buffers和cached的区别。参考(http://blog.chinaunix.net/uid--id-3564801.html)给出的buffers和cached的区别说明,(a) buffers是指用来给块设备做的缓冲大小,他只记录文件系统的metadata以及 tracking in-flight pages。cached是用来给文件做缓冲。(b) buffers是用来存储目录里面有什么内容,权限等等。而cached直接用来记忆我们打开的文件,比如先后执行两次命令#man X ,你就可以明显的感觉到第二次的开打的速度快很多。而buffers随时都在增加,比如先后两次使用ls /dev后,就会发现第二次执行的速度会较第一次快。从不同角度,对内存占用率有不同的理解,以下图为例,(1) 站在操作系统的角度,buffer和cache的内存是属于分配的内存,因此内存占用率计算方法=used/total*100%。(2) 站在使用者的角度上看,buffer和cache的内存是可以被重用的,因此内存占用率计算方法=(used-buffers-cached)/total*100%。因此对于开始的问题,我们关注的是应用可用内存,所以我们需要监控关注的内存实际占用率应该为,(used-buffers-cached)/total*100%=(3)/%,再进一步,关于如何监控内存使用,无论从网上的资料,还是实际的工作经验,都会有各种不同的方法,这儿我只是简单说一下,如何使用Python监控内存使用率。(1) 不使用任何第三方库实现思路很简单,就是执行free指令,解析回显,得出used、buffers、cached、total这些参数值,再进行计算。output = os.popen('free -m')output.readline()line = ','.join(output.readline().split()).split(',')total = float(line[1])used = float(line[2])buffers = float(line[5])cached = float(line[6])percent = int(round((used - buffers - cached) / total * 100))结果向上取整,例如25%,注意需要使用float浮点型,否则计算percent的时候未乘以100前就已经是0了。(2) 使用第三方库psutilpsutil是一个跨平台的进程管理,首先需要安装,psutil安装之前需要安装python-devel,均需要root用户,我的操作系统是Linux 6.5,Python版本2.6.6,这两个包的版本则为(a) python-devel-2.6.6-51.el6.x86_64.rpm(b) psutil-2.0.0使用第三方库,这问题就非常容易了,import psutilpercent = mem.percent这里的mem.percent=(mem.total - mem.available) / mem.total * 100,其中mem.available=mem.free + mem.buffers + mem.cached,和(1)中计算方法是一致的。其实psutil可以执行几乎所有,系统监控相关的指令操作,Github地址,/giampaolo/psutil/这篇文章的介绍非常清晰,/p/64e265f663f6psutil(Python system and process utilities)是一个跨平台的进程管理和系统工具的python库,可以处理系统CPU,memory,disks,network等信息。主要用于系统资源的监控,分析,以及对进程进行一定的管理。通过psutil可以实现如ps,top,lsof,netstat,ifconfig, who,df,kill,free,nice,ionice,iostat,iotop,uptime,pidof,tty,taskset,pmap。在Linux,windows,OSX,freebsdSun Solaris等系统上工作,最新的版本python是要高于2.6(Python 2.4 Python2.5 可以用2.1.3版本)总结:1. Linux下实际我们关注的是,系统可用内存的占用率,计算方法为(used-buffers-cached)/total*100%,并不是执行free指令中free显示的部分。2. 内存占用率监控Python实现,可以使用执行free指令来解析输出,若可以使用psutil第三方库,则更为简便。如果您觉得此篇文章对您有帮助,欢迎关注微信公众号:bisal的个人杂货铺,您的支持是对我最大的鼓励!共同学习,共同进步:)
我的热门文章遇到个python进程占用内存太多的问题 | 盛大创新院团队博客 | 数据,更懂人心
我的图书馆
遇到个python进程占用内存太多的问题 | 盛大创新院团队博客 | 数据,更懂人心
在几个前辈的影响下,也开始用起了python,上手较快,并且觉得内存回收这些个烦心事自己也不用过问,自有解释器来完成。直到开始抓取某吧的帖子时才遇到问题。
抓取的思路很简单:获取某个分类下的所有的吧; 获取某个吧下的所有帖子;获取某个帖子的所有回复页。并且上面的每个步骤都是一个单独的接口实现。但是程序跑起来总是被莫名杀掉,并且dmesg查看会有“out of memory”的信息,应该是进程占用内存太大,被系统强制停掉。想着觉得不可思议,估算下,一个帖子只存储link和anchor,平均算上256byte,一个吧最多500w帖子,才用1G+多些,怎么会在一台16G的机器上down掉的呢(该机器虽然有其他程序,但每次进程退出时至少都占用了7G+).
于是开始找了些python的内存检测相关的工具和说明的页面看了看。
工具方面:
1、尝试valgrind检查,”确实看到很多xx are still reachable”的日志,而且这个xx数字越往后越大,囧。但是这些trace都是python解释器调用底层接口,也无法看懂(有个网页说到python2.x解释器可能存在内存泄露但还是先从自己程序找问题)。
2、cprofile分析:输出文件里有各个接口的调用次数和平均处理时间之类的,更像是解决性能的辅助工具。
3、尝试用gc模块的gc.collect接口进行强制的内存回收,没有效果。
4、尝试meliae:在上面的每次循环处理之后打印各个对象的占用情况,发现最多的对象都是beautifulsoup的Navigating占用了快80%的内存,于是在每次soup的find的object使用完后都强制del,仍然没有效果(感觉这个检测结果有点误导性)。
这个时候回头再仔细想了想之前的帖子里讲到的python的内存虽然会自动回收,但是回收完之后的内存并不是还给系统,而仍然是作为python的内存池。所以最根本的解决方法就是如何尽量少的让python从系统申请内存和复用自身的内存池资源。于是将上面的抓取流程稍微改动一下,每次并不是获取完一个吧的所有帖子,而且每次只获取一页的帖子,重新运行,便发现python的内存占用始终维持在0.2%左右了。
某种程序上来说,这种内存管理方式并没有能解释得通为何第一种写法会占用越来越大的内存;不过后来的解决方法却可以作为以后写python脚本时内存考虑的一个指导点。同时几种工具使用一遍,也是个不错的经历。更高追求的同学还可以关注下如何高效地释放内存的方式,我还没有尝试过。
TA的最新馆藏[转]&
喜欢该文的人也喜欢Python 对象内存占用 - CSDN博客
Python 对象内存占用
转自:/Lvkun/archive//python_object_memory_usage.html
def fuction(): return print isinstance(True, object) print isinstance(0, object) print isinstance('a', object) print isinstance(fuction, object)
import sys print sys.version
本文已收录于以下专栏:
相关文章推荐
由于python中的整数对象记录的整数值是不可变的,所以在名字a的值不断变化的过程中,就就涉及到了多次对象的创建和销毁。所以python为整数对象申请空间进行了两种优化:
优化1:为通用整数对象存储池...
python对象内存分析
一、python内建对象
python内建对象占用内存的情况又分为定长对象与非定长对象(变长)
1.1 定长对象,对象在内存中所占大小不会变化的对象
包括int,fl...
问题说明:
以前在使用zip(a,b)时,a,b都是一个非常大的list。使用python2解释器时,执行zip(a,b)都会提示,内存错误。后来找到了原因,python2的zip(a,b)直接是生...
转载> /magialmoon/p/3757767.html
一个Java对象到底占用多大内存?
在网上搜到了一篇博客讲的非常好:http://yuey...
原文地址:/a/3272
本文深入分析并验证了不同Java对象占用内存空间大小的情况。对于不同的jvm实现,Java对象占...
static_cast和dynamic_cast是C++的类型转换操作符。编译器隐式执行的任何类型转换都可以由static_cast显式完成,即父类和子类之间也可以利用static_cast进行转换。...
一个Java对象到底占用多大内存?
最近在读《深入理解Java虚拟机》,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用...
Java计算一个对象占用内存的大小
C++中类对象的内存布局和占用空间
他的最新文章
讲师:董岩
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)浅谈Python 对象内存占用
投稿:jingxian
字体:[ ] 类型:转载 时间:
下面小编就为大家带来一篇浅谈Python 对象内存占用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
一切皆是对象
在 Python 一切皆是对象,包括所有类型的常量与变量,整型,布尔型,甚至函数。 参见stackoverflow上的一个问题 Is everything an object in python like ruby
代码中即可以验证:
# everythin in python is object def fuction(): return print isinstance(True, object) print isinstance(0, object) print isinstance('a', object) print isinstance(fuction, object)
Python 在 sys 模块中提供函数 getsizeof 来计算 Python 对象的大小。
sys.getsizeof(object[, default])
以字节(byte)为单位返回对象大小。 这个对象可以是任何类型的对象。 所以内置对象都能返回正确的结果 但不保证对第三方扩展有效,因为和具体实现相关。
getsizeof() 调用对象的 __sizeof__ 方法, 如果对象由垃圾收集器管理, 则会加上额外的垃圾收集器开销。
当然,对象内存占用与 Python 版本以及操作系统版本关系密切, 本文的代码和测试结果都是基于 windows7 32位操作系统。
import sys print sys.version
2.7.2 (default, Jun 24 :10) [MSC v.1500 32 bit (Intel)]
•布尔型
print 'size of True: %d' % (sys.getsizeof(True)) print 'size of False: %d' % (sys.getsizeof(False))
size of True: 12 size of False: 12
•整型
# normal integer print 'size of integer: %d' % (sys.getsizeof(1)) # long print 'size of long integer: %d' % (sys.getsizeof(1L)) print 'size of big long integer: %d' % (sys.getsizeof(100000L)) 输出:
size of integer: 12x size of long integer 1L: 14 size of long integer 100000L: 16
可以看出整型占用12字节,长整型最少占用14字节,且占用空间会随着位数的增多而变大。 在2.x版本,如果整型类型的值超出sys.maxint,则自动会扩展为长整型。而 Python 3.0 之后,整型和长整型统一为一种类型。
•浮点型
print 'size of float: %d' % (sys.getsizeof(1.0))
size of float: 16
浮点型占用16个字节。超过一定精度后会四舍五入。
参考如下代码:
print 1. print 1.
•字符串
# size of string type print '\r\n'.join(["size of string with %d chars: %d" % (len(elem), sys.getsizeof(elem)) for elem in ["", "a", "ab"]]) # size of unicode string print '\r\n'.join(["size of unicode string with %d chars: %d" % (len(elem), sys.getsizeof(elem)) for elem in [u"", u"a", u"ab"]])
size of string with 0 chars: 21 size of string with 1 chars: 22 size of string with 2 chars: 23 size of unicode string with 0 chars: 26 size of unicode string with 1 chars: 28 size of unicode string with 2 chars: 30
普通空字符串占21个字节,每增加一个字符,多占用1个字节。Unicode字符串最少占用26个字节,每增加一个字符,多占用2个字节。
•列表
# size of list type print '\r\n'.join(["size of list with %d elements: %d" % (len(elem), sys.getsizeof(elem)) for elem in [[], [0], [0,2], [0,1,2]]])
size of list with 0 elements: 36 size of list with 1 elements: 40 size of list with 2 elements: 44 size of list with 3 elements: 48
可见列表最少占用36个字节,每增加一个元素,增加4个字节。但要注意,sys.getsizeof&函数并不计算容器类型的元素大小。比如:
print 'size of list with 3 integers %d' % (sys.getsizeof([0,1,2])) print 'size of list with 3 strings %d' % (sys.getsizeof(['0','1','2']))
size of list with 3 integers 48 size of list with 3 strings 48
容器中保存的应该是对元素的引用。如果要准确计算容器,可以参考。使用其给出的&total_size&函数:
print 'total size of list with 3 integers %d' % (total_size([0,1,2])) print 'total size of list with 3 strings %d' % (total_size(['0','1','2']))
total size of list with 3 integers 84 total size of list with 3 strings 114
可以看出列表的空间占用为 基本空间 36 + (对象引用 4 + 对象大小) * 元素个数。
另外还需注意如果声明一个列表变量,则其会预先分配一些空间,以便添加元素时增加效率:
li = [] for i in range(0, 101): print 'list with %d integers size: %d, total_size: %d' % (i, getsizeof(li), total_size(li)) li.append(i)
•元组
基本与列表类似,但其最少占用为28个字节。
•字典
字典的情况相对复杂很多,具体当然要, 另外 非常值得仔细阅读。
基本情况可以参考[stackoverflow] 的问题 中的一些回答:
•字典最小拥有8个条目的空间(PyDict_MINSIZE);
•条目数小于50,000时,每次增长4倍;
•条目数大于50,000时,每次增长2倍;
•键的hash值缓存在字典中,字典调整大小后不会重新计算;
每接近2/3时,字典会调整大小。
以上这篇浅谈Python 对象内存占用就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 如何解决内存占用过高 的文章

 

随机推荐