python变量的内存机制

python变量的内存机制

作为一门简单易用的语言,且配备海量的库,python可谓是程序员手中的掌中宝,编程本身就是一种将人类思维转化为计算机思维的技术,如果不需要去追求极致的运行效率同时又不限制于计算机内存空间,python无疑是目前最方便的语言了。

作为一个合格的程序员,自然是要知其然并知其所以然,除了能够应用python来放飞自我之外,同时也要探究python其内部的运行原理,首当其冲的python编程中必须要用到的变量以及背后的运行机制。

注:以下示例在linux平台下编写,使用python2.7

引用机制

python的变量-内存模型更像是C++中的引用机制,python中的每个变量不一定占用内存空间,变量更像是一份内存的引用,通过这个变量可以访问到内存中的数据,举个例子:

>>>a=10
>>>b=a
>>>c=[1,2,3,4]
>>>d=c
>>>print "%x%x"  %(id(a),id(b))
>>>print "%x%x"  %(id(c),id(d))

输出结果:

b51080.b51080
7f28bf69b758.7f28bf69b758  

其中id()是python的系统函数,返回对象的内存起始地址。

从结果可以看出,a与b,c与d变量对应的地址事实上为同一个地址,也就是当我们使用变量a和b时,使用的是同一个对象,而a,b是这个对象的引用,我们可以通过系统函数sys.getrefcount()来查看一个对象的引用数量:

>>>import sys
>>>a=257
>>>print sys.getrefcount(a)
>>>b=a
>>>print sys.getrefcount(a)

输出结果:

2
3

显然,这个结果并不在我们的预料当中,由于a和b在同一个地址,结果应该是1、2,为什么是2,3呢?

这是因为在sys.getrefcount()函数调用时,a作为参数也被引用了一次,所以出现了2、3的结果。

缓存小数据机制

上面讲了python变量赋值时的内存机制,事情就这么完美结束了吗?

并没有!!!

我们再来看一个例子:

>>> a=10
>>> b=10
>>> print "%x.%x" %(id(a),id(b))

输出结果:

b51080.b51080

看到这个结果,我缓缓摘下我的眼镜,拿95%浓度的医用酒精仔仔细细擦了三遍之后再戴上看,没看错!这两个变量还是同一个地址内容的引用,这一次两个变量的初始化是独立的,并非赋值初始化,为什么两个变量还是同一个地址的引用呢?

答案是:

在Python中,Python会有一个缓存对象的机制,以便重复使用。当我们创建多个等于1的引用时,实际上是让所有这些引用指向同一个对象,以达到节省资源的目的  

原来是这样!!!

但是仔细一想,这不对吧?如果每个数据都进行缓存,那岂不是对内存空间的极度浪费?还是说内存回收机制会过一段时间回收一次垃圾内存?
我们再来看下面一个例子:

>>> a=100
>>> b=100
>>> print "%d%d" %(id(a),id(b))
>>> a=256
>>> b=256
>>> print "%d%d" %(id(a),id(b))
>>> a=257
>>> b=257
>>> print "%d%d" %(id(a),id(b))

输出结果:

5223836.5223836
5225932.5225932
5241840.5241864  

从结果来看,当a小于256时,这个值会被系统缓存循环利用,而当a>256时,系统并不会进行缓存(当然不仅仅是三次实验的结果,博主后续还试了很多值,就不一一列出了)

我们来用另一种方法来验证这个问题,即sys.getrefcount():

>>>import sys
>>>a=10
>>>print sys.getrefcount(a)
>>>a=257
>>>print sys.getrefcount(a)

输出结果为:

15
2

结果显而易见,10这个值被系统缓存,且在别处引用了多次,而257这个值为2(为什么为2而不是1在上面有解释)

那么问题又来了,如果是其他类型的数据呢?我们接着看

>>>a="downey"
>>>b="downey"
>>>print "%d%d" %(id(a),id(b))

结果为:

39422528.39422528

短字符串也会有缓存机制

然后是list:

>>>a=[1,2,3]
>>>b=[1,2,3]
>>>print "%d%d" %(id(a),id(b))
39704576.39745176

list并没有缓存机制,从这里可以看出,python的缓存机制并不针对所有变量类型

变量缓存结论

根据各种实验以及多方查证,结果表明:

  • python的变量其实是一种堆内存的引用,可以理解为一个实体的标签,而在不同变量之间的拷贝复制(如a=b),他们所表示的对象实体是同一个
  • python会对-5-256(包括256)的整型数据和短字符串进行缓存以节省多次分配销毁的开销

看到这里,喜欢思考的朋友们不禁就要问了,缓存这些整型数据和短字符串真的对性能有明显提升吗?python代码中能有多少个整型变量?

答案是:整型变量对应整型的内存对象,但是整型的内存对象并不仅仅对应整型的变量类型,容器中的整形元素可能也是整形变量的引用

如果你还有疑惑,我们来看看下面的例子:

>>> import sys
>>> a=1
>>> sys.getrefcount(a)
128
>>> b=[1,2,3]
>>> sys.getrefcount(a)
129

从打印的结果可以看出,整型变量a=1,表示a指向对象1,为1的引用,b[0]也被初始化为1,同样的,b[0]同时也是对象1的引用,对于所有容器而言,都是这种形式,看到这里,各位观众老爷们应该是有所理解了吧。

内存回收

既然说到了内存机制,必然涉及到分配和回收的机制,内存分配就很简单,在定义对象的时候用到进行内存的分配,而内存的回收则没那么简单,因为在内存回收的过程中,python无法执行其他任务,所以频繁地内存回收会导致严重的效率问题,而内存回收间隔时间过长则会导致内存浪费严重,所以一般只有在特定时间内启动内存回收。

python运行时,会记录下来分配和释放的次数,只有当两个值的差大于某个数值时,即

分配次数-释放次数>触发回收的阈值

时,python进行垃圾回收,我们可以使用get_threshold()方法来获取阈值:

>>>import gc
>>>print gc.get_threshold()

输出结果:

(700,10,10)

这个700便是触发内存回收的阈值。但是后面的两个10又是什么意思呢?

这也是内存回收中的一种机制,叫做分代回收,这一策略的基本假设是:存在时间越久的对象,越不可能成为垃圾对象,即给予一些长期使用的对象更多信任。

Python将所有的对象分为0,1,2三代。所有的新建对象都是0代对象。当某一代对象经历过垃圾回收,依然存活,那么它就被归入下一代对象。垃圾回收启动时,一定会扫描所有的0代对象。如果0代经过一定次数垃圾回收,那么就启动对0代和1代的扫描清理。当1代也经历了一定次数的垃圾回收后,那么会启动对0,1,2,即对所有对象进行扫描

这两个次数即上面get_threshold()返回的(700, 10, 10)返回的两个10。也就是说,每10次0代垃圾回收,会配合1次1代的垃圾回收;而每10次1代的垃圾回收,才会有1次的2代垃圾回收。

我们也可以手动地调整触发回收的阈值,聪明的朋友们可以猜到这个方法了,既然有get,必然相对应的就是set:

import gc
gc.set_threshold(600,8,7)

除了被动地等待系统回收,当然也可以手动地进行内存回收:

import gc
gc.collect()  

其实java也好,python也好,每一种语言的内存机制将从根本上影响语言的执行效率,所以在内存的处理上会有很多更加复杂的细节,这里只是介绍了一个大体的框架,班门弄斧,欢迎路过的大神们指正和补充。

好了,关于python变量内存机制的问题就到此为止了,如果朋友们对于这个有什么疑问或者发现有文章中有什么错误,欢迎留言

个人邮箱:linux_downey@sina.com
原创博客,转载请注明出处!

祝各位早日实现项目丛中过,bug不沾身.
(完)

原文地址:https://www.cnblogs.com/downey-blog/p/10482955.html

时间: 2024-10-29 15:04:33

python变量的内存机制的相关文章

014 Python变量的内存管理

Python变量内存管理 1.变量存在哪里 1.如果我们定义了一个变量,而我们没有用python解释器取运行的时候,这个变量其实就是很普通的几个字符而已.而当我们用Python解释器取运行它的时候,那字符进入了内存,才会有变量这个概念.也就是说变量是存放在内存当中的. 2.但是说变量只是存在内存中并没有很具体,实际上在每定义一个变量就会在这个内存的大空间中开辟一个小空间 2.引用计数 1.引用计数是针对变量值的 2.比如定义一个变量 height = 180 x = height # x是在引用

python中的内存机制

首先要明白对象和引用的概念 (例子:a=1, a为引用,1为对象,对象1的引用计数器为1,b=1此时内存中只有一个对象1,a,b都为引用,对象的引用计数器此时为2,因为有两个引用) a=1,b=1 id(a)=id(b) #短的字符串,数字python在内存中是一个对象 a=[],b=[] id(a)!=id(b) #字典,数组这样的对象在内存中python会new两个不同的对象 a="new a string" b="new a string" #长的字符串pyt

python学习之内存机制

不可变对象(字符串.元组) 1. a = 1 首先在内存中创建对象1,并记录对象的引用计数为1次. id(a) 查看变量a引用的对象的内存地址 2. b = 1 内存中已存在对象1,变量b引用对象1,则对象1的引用计数为2次. id(b) 变量b和变量a引用的是同一个对象,内存地址相同. 3. a = a + 1 在内存中创建对象2,变量a不再引用原有对象1(引用次数减为1),开始引用对象2(引用次数增为1) a = 1 重新执行a=1,a依然指向原有对象(因为还是1) 注意:仅对短字符有效,长

python基础(变量,常量,python变量内存管理,变量的三个特征,花式赋值,注释 )

python基础 变量 定义:变量用来描述世间万物变化的状态 组成: 变量名:接收变量值 赋值符号:把变量值赋值给变量名 变量值:就是一个数值 注意: 变量名由数字/字母/下划线组成,不能以数字开头 变量名不能以下关键字命名 ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global',

Python 中变量与内存的关系

老手都是从新手一路过来的,提起Python中难以理解的概念,可能很多人对于Python变量赋值的机制有些疑惑,不过对于习惯于求根究底的程序员,只有深入理解了某个事物本质,掌握了它的客观规律,才能得心应手.运用自如,进阶更高层次来看待这个事物,此刻“庖丁解牛”这个成语能够贴切表达这个意思,你看见的是整头的牛,而我看见的是牛的内部肌理筋骨,就是这个状态!!! 那么为什么Python变量赋值的机制难以理解呢? 我想可能是我们的思维被C语言变量赋值的机制所固化了.在C语言中变量所分配到的地址是内存空间中

操作系统,编程语言分类,执行python两种方式,变量,内存管理,定义变量的三个特征

操作系统 1.什么是操作系统 操作系统位于计算机硬件与应用软件之间 是一个协调.管理.控制计算机硬件资源与软件资源的控制程序 2.为何要有操作系统? 1.控制硬件 2.把对硬件的复杂的操作封装成优美简单的接口(文件),给用户或者应用程序去使用 注意:一套完整的计算机系统包含三部分 应用程序:qq,暴风影音,快播 操作系统:windows,linux,unix 计算机硬件 强调: 我们以后开发的都是应用程序 应用程序无法直接操作硬件,但凡要操作硬件,都是调用操作系统的接口 编程语言分类 1.机器语

python变量存储的缓存机制

python变量存储的缓存机制 1.  在同一文件(模块)里 1.对于整型而言,-5~正无穷范围内的相同值 id一致 2.对于浮点数而言,非负数范围内的相同值 id一致 3.布尔值而言,值相同情况下,id一致 4.复数的id标识都不相同(在 实数+虚数 这样的结构中) 5.字符串而言,字符串值相同情况下,id一致 6.列表,元组,字典,集合无论什么情况 id标识都不同(但空元组的id标识一样) 2.  不同文件(模块)里,部分数据驻留小数据池中 python提前在内存中创建了-5~256 范围的

Python变量内存管理

一.变量存哪了? x=10 当我们在p1.py中定义一个变量x = 10,那么计算机把这个变量值10存放在哪里呢了?我们回顾计算机的三大核心组件为:CPU.内存和硬盘.一定不是CPU,那是存放在内存还是硬盘中了呢?我们再回顾变量运行的三个过程,如果我们没有使用python解释器运行p1.py这个文件,那么x=10很明显只是很普通的四个字符x.=.1.0.而只有Python解释器运行了这个文件,那字符进入了内存,才会有变量这个概念.也就是说变量是存放在内存当中的. 变量存放在内存中这句话太宽泛了,

python变量内存浅析

1. Python变量 如果把单一值变量称为一维变量,把可以扩展元素的变量称为多维变量,则python的变量可以划分如下: 变量维度 Python变量 说明 一维 数字 int(有符号整型) 数字类型可以做转换 long(长整型[也可以代表八进制和十六进制]) float(浮点型) complex(复数) 字符串 字符串有丰富的运算符和内嵌函数: 有格式化输出: 二维 列表 除了元祖外,列表和字典可以灵活的扩展元素 元组 字典 2. Python变量的赋值处理 这里主要分析情况为,将原始变量赋值