python的内存管理机制

Python内存管理机制
本文介绍了Python内存管理机制的三大方面:垃圾回收、引用计数和内存池机制。详细解释了Python如何通过引用计数跟踪对象的使用情况,以及垃圾回收器如何处理不再使用的对象。

先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲

(1)垃圾回收

(2)引用计数

(3)内存池机制

一、垃圾回收:

python不像C++,Java等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值。对Python语言来讲,对象的类型和内存都是在运行时确定的。这也是为什么我们称Python语言为动态类型的原因(这里我们把动态类型可以简单的归结为对变量内存地址的分配是在运行时自动判断变量类型并对变量进行赋值)。

二、引用计数:

Python采用了类似Windows内核对象一样的方式来对内存进行管理。每一个对象,都维护这一个对指向该对对象的引用的计数。如图所示(图片来自Python核心编程)

x = 3.14

y = x

 

我们首先创建了一个对象3.14, 然后将这个浮点数对象的引用赋值给x,因为x是第一个引用,因此,这个浮点数对象的引用计数为1. 语句y = x创建了一个指向同一个对象的引用别名y,我们发现,并没有为Y创建一个新的对象,而是将Y也指向了x指向的浮点数对象,使其引用计数为2.

我们可以很容易就证明上述的观点:

 

变量a 和 变量b的id一致(我们可以将id值想象为C中变量的指针).

我们援引另一个网址的图片来说明问题:对于C语言来讲,我们创建一个变量A时就会为为该变量申请一个内存空间,并将变量值 放入该空间中,当将该变量赋给另一变量B时会为B申请一个新的内存空间,并将变量值放入到B的内存空间中,这也是为什么A和B的指针不一致的原因。如图:

              

 int A = 1                       int A = 2

而Python的情况却不一样,实际上,Python的处理方式和Javascript有点类似,如图所示,变量更像是附在对象上的标签(和引用的定义类似)。当变量被绑定在一个对象上的时候,该变量的引用计数就是1,(还有另外一些情况也会导致变量引用计数的增加),系统会自动维护这些标签,并定时扫描,当某标签的引用计数变为0的时候,该对就会被回收。

                       

      a = 1                         a = 2                         b = a

 

 三、内存池机制

 

Python的内存机制以金字塔行,-1,-2层主要有操作系统进行操作,

  第0层是C中的malloc,free等内存分配和释放函数进行操作;

  第1层和第2层是内存池,有Python的接口函数PyMem_Malloc函数实现,当对象小于256K时有该层直接分配内存;

  第3层是最上层,也就是我们对Python对象的直接操作;

在 C 中如果频繁的调用 malloc 与 free 时,是会产生性能问题的.再加上频繁的分配与释放小块的内存会产生内存碎片. Python 在这里主要干的工作有:

  如果请求分配的内存在1~256字节之间就使用自己的内存管理系统,否则直接使用 malloc.

  这里还是会调用 malloc 分配内存,但每次会分配一块大小为256k的大块内存.

  经由内存池登记的内存到最后还是会回收到内存池,并不会调用 C 的 free 释放掉.以便下次使用.对于简单的Python对象,例如数值、字符串,元组(tuple不允许被更改)采用的是复制的方式(深拷贝?),也就是说当将另一个变量B赋值给变量A时,虽然A和B的内存空间仍然相同,但当A的值发生变化时,会重新给A分配空间,A和B的地址变得不再相同

而对于像字典(dict),列表(List)等,改变一个就会引起另一个的改变,也称之为浅拷贝

附:

引用计数增加

1.对象被创建:x=4

2.另外的别人被创建:y=x

3.被作为参数传递给函数:foo(x)

4.作为容器对象的一个元素:a=[1,x,'33']

引用计数减少

1.一个本地引用离开了它的作用域。比如上面的foo(x)函数结束时,x指向的对象引用减1。

2.对象的别名被显式的销毁:del x ;或者del y

3.对象的一个别名被赋值给其他对象:x=789

4.对象从一个窗口对象中移除:myList.remove(x)

5.窗口对象本身被销毁:del myList,或者窗口对象本身离开了作用域。

 

垃圾回收

1、当内存中有不再使用的部分时,垃圾收集器就会把他们清理掉。它会去检查那些引用计数为0的对象,然后清除其在内存的空间。当然除了引用计数为0的会被清除,还有一种情况也会被垃圾收集器清掉:当两个对象相互引用时,他们本身其他的引用已经为0了。

2、垃圾回收机制还有一个循环垃圾回收器, 确保释放循环引用对象(a引用b, b引用a, 导致其引用计数永远不为0)。

 

参考:

[1] Python 2.7.8 documentation memory management

[2]深入详解python传值问题及内存管理机制-优快云

[3]Python内存池管理与缓冲池设计 - 张知临的专栏

[4]理解python变量和内存管理 

 


http://www.cnblogs.com/CBDoctor/p/3781078.html

### Python 内存管理机制原理 Python内存管理主要依赖于 **引用计数** 和 **垃圾回收器** 来实现自动化资源管理。以下是对其核心组件及其工作方式的深入解析: #### 1. 引用计数 (Reference Counting) Python 使用引用计数来跟踪每个对象被引用的次数。每当一个对象被创建或者赋值给一个新的变量时,该对象的引用计数会增加;当某个引用失效(如变量重新赋值或超出作用域)时,引用计数减少。如果某对象的引用计数降为零,则表示没有任何引用指向它,此时可以安全地销毁该对象并释放其所占用的内存。 这种机制的优点在于简单高效,能够及时释放不再使用的对象所占有的内存空间[^1]。然而,单纯依靠引用计数存在一个问题——无法处理循环引用的情况。因此,Python 还引入了更复杂的垃圾回收算法来解决这个问题。 #### 2. 垃圾回收器 (Garbage Collector, GC) 为了应对由循环引用引起的问题,Python 实现了一个基于 **标记-清除 (Mark-and-Sweep)** 和 **分代收集 (Generational Collection)** 的垃圾回收系统。 ##### 标记-清除 此方法分为两个阶段: - 首先,“标记”所有可能存活的对象; - 接着,“清除”那些未被标记的对象,即认为这些对象已经死亡且可回收。 这种方法能有效检测到因循环引用而导致的标准引用计数法无法识别的废弃对象集合[^2]。 ##### 分代收集 Python 将对象按照它们的存在时间划分为不同的世代(Generation)。新创建的对象属于第0代,经过一次GC扫描后仍存在的对象会被移动至更高一代(依次升级到第1代、第2代),直到达到最高级别为止。通常情况下,较年轻的对象更容易成为垃圾,所以针对低龄代执行频繁但轻量级的清理操作即可满足需求,而对于高龄代则采取较少频率却更加彻底的方式进行检查和整理[^3]。 #### 3. 内存池机制 (Memory Pool Mechanism) 除了上述两种技术外,CPython 解释器还采用了一种称为“内存池”的优化手段用于小型固定大小数据类型的快速分配与释放。具体来说,就是预先划分好一定数量的小块连续存储区域供后续重复利用,从而避免每次都需要向操作系统请求新的堆地址所带来的开销。这尤其适用于像整型这样的短生命周期数值实例上。 ```python import sys class MyClass: pass obj = MyClass() print(sys.getrefcount(obj)) # 输出当前 obj 对象的引用计数 del obj # 删除引用,降低引用计数直至触发销毁条件 ``` 以上代码展示了如何查看单个自定义类实例在其生命期内的变化情况以及最终消失的过程。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值