python的内存管理机制

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python的内存管理机制相关的知识,希望对你有一定的参考价值。

参考技术A 论坛

活动

招聘

专题

打开CSDN APP
Copyright © 1999-2020, CSDN.NET, All Rights Reserved

登录

XCCS_澍
关注
Python 的内存管理机制及调优手段? 原创
2018-08-05 06:50:53

XCCS_澍

码龄7年

关注
内存管理机制:引用计数、垃圾回收、内存池。
一、引用计数:
    引用计数是一种非常高效的内存管理手段, 当一个 Python 对象被引用时其引用计数增加 1, 当其不再被一个变量引用时则计数减 1. 当引用计数等于 0 时对象被删除。
二、垃圾回收 :
1. 引用计数
      引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集技术。当 Python 的某个对象的引用计数降为 0 时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如某个新建对象,它被分配给某个引用,对象的引用计数变为 1。如果引用被删除,对象的引用计数为 0,那么该对象就可以被垃圾回收。不过如果出现循环引用的话,引用计数机制就不再起有效的作用了
2. 标记清除
     如果两个对象的引用计数都为 1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的,也就是说,它们的引用计数虽然表现为非 0,但实际上有效的引用计数为 0。所以先将循环引用摘掉,就会得出这两个对象的有效计数。
3. 分代回收
     从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。
参考技术B

python的存储问题

(1)由于python中万物皆对象,所以python的存储问题是对象的存储问题,并且对于每个对象,python会分配一块内存空间去存储它

(2)对于整数和短小的字符等,python会执行缓存机制,即将这些对象进行缓存,不会为相同的对象分配多个内存空间

(3)容器对象,如列表、元组、字典等,存储的其他对象,仅仅是其他对象的引用,即地址,并不是这些对象本身

关于引用计数器

(1)一个对象会记录着引用自己的对象的个数,每增加一个引用,个数加一,每减少一个引用,个数减一

(2)查看引用对象个数的方法:导入sys模块,使用模块中的getrefcount(对象)方法,由于这里也是一个引用,故输出的结果多1

(3)增加引用个数的情况:1.对象被创建p = Person(),增加1;2.对象被引用p1 = p,增加1;3.对象被当作参数传入函数func(object),增加2,原因是函数中有两个属性在引用该对象;4.对象存储到容器对象中l = [p],增加1

(4)减少引用个数的情况:1.对象的别名被销毁del p,减少1;2.对象的别名被赋予其他对象,减少1;3.对象离开自己的作用域,如getrefcount(对象)方法,每次用完后,其对对象的那个引用就会被销毁,减少1;4.对象从容器对象中删除,或者容器对象被销毁,减少1

(5)引用计数器用法:

import sys
class Person(object):
pass
p = Person()
p1 = p
print(sys.getrefcount(p))
p2 = p1
print(sys.getrefcount(p))
p3 = p2
print(sys.getrefcount(p))
del p1
print(sys.getrefcount(p))

多一个引用,结果加1,销毁一个引用,结果减少1

(6)引用计数器机制:利用引用计数器方法,在检测到对象引用个数为0时,对普通的对象进行释放内存的机制

关于循环引用问题

(1)循环引用即对象之间进行相互引用,出现循环引用后,利用上述引用计数机制无法对循环引用中的对象进行释放空间,这就是循环引用问题

(2)循环引用形式:

class Person(object):
pass
class Dog(object):
pass
p = Person()
d = Dog()
p.pet = d
d.master = p

即对象p中的属性引用d,而对象d中属性同时来引用p,从而造成仅仅删除p和d对象,也无法释放其内存空间,因为他们依然在被引用。深入解释就是,循环引用后,p和d被引用个数为2,删除p和d对象后,两者被引用个数变为1,并不是0,而python只有在检查到一个对象的被引用个数为0时,才会自动释放其内存,所以这里无法释放p和d的内存空间

关于垃圾回收(底层层面--原理)

(1)垃圾回收的作用:从经过引用计数器机制后还没有被释放掉内存的对象中,找到循环引用对象,并释放掉其内存

(2)垃圾回收检测流程:

一.任何找到循环引用并释放内存:1.收集所有容器对象(循环引用只针对于容器对象,其他对象不会产生循环引用),使用双向链表(可以看作一个集合)对这些对象进行引用;2.针对每一个容器对象,使用变量gc_refs来记录当前对应的应用个数;3.对于每个容器对象,找到其正在引用的其他容器对象,并将这个被引用的容器对象引用计数减去1;4.经过步骤3后,检查所有容器对象的引用计数,若为0,则证明该容器对象是由于循环引用存活下来的,并对其进行销毁

二.如何提升查找循环引用过程的性能:由一可知,循环引用查找和销毁过程非常繁琐,要分别处理每一个容器对象,所以python考虑一种改善性能的做法,即分代回收。首先是一个假设--如果一个对象被检测了10次还没有被销毁,就减少对其的检测频率;基于这个假设,提出一套机制,即分代回收机制。

通过这个机制,循环引用处理过程就会得到很大的性能提升

关于垃圾回收时机(应用层面--重点)

(1)自动回收:

(2)手动回收:这里要使用gc模块中的collect()方法,使得执行这个方法时执行分代回收机制

import objgraph
import gc
import sys
class Person(object):
pass
class Dog(object):
pass
p = Person()
d = Dog()
p.pet = d
d.master = p
del p
del d
gc.collect()
print(objgraph.count("Person"))
print(objgraph.count("Dog"))

其中objgraph模块的count()方法是记录当前类产生的实例对象的个数

关于内存管理机制的总结(重点)

综上所述,python的内存管理机制就是引用计数器机制和垃圾回收机制的混合机制。

参考技术C

对于Python来说,内存管理涉及所有包含Python对象和堆。 Python内存管理器在内部确保对堆的管理和分配。 Python内存管理器具有不同的组件,可处理各种动态存储管理方面,如共享,分段,预分配或缓存。

在最低级别,原始内存分配器确保堆中有足够的空间通过与操作系统的内存管理器交互来存储所有与Python相关的数据。在原始内存分配器之上,几个特定于对象的分配器在同一堆上运行,并实现适合于每种对象类型的特性的不同内存管理策略。

例如,整数对象在堆内的管理方式与字符串,元组或字典不同,因为整数意味着不同的存储要求和速度/空间权衡。因此,Python内存管理器将一些工作委托给特定于对象的分配器,但确保后者在堆的边界内运行。

重要的是要理解Python堆的管理是由解释器本身执行的,并且用户无法控制它,即使它们经常操作对象指针到该堆内的内存块。 Python内存管理器通过本文档中列出的Python / C API函数按需执行Python对象和其他内部缓冲区的堆空间分配。

为了避免内存损坏,扩展编写器不应该尝试使用C库导出的函数对Python对象进行操作:malloc(),calloc(),realloc()和free()。这将导致C分配器和Python内存管理器之间的混合调用带来致命的后果,因为它们实现了不同的算法并在不同的堆上运行。

在大多数情况下,我们建议从Python堆中分配内存,因为后者受Python内存管理器的控制。 例如,当使用C编写的新对象类型扩展解释器时,这是必需的。使用Python堆的另一个原因是希望通知Python内存管理器有关扩展模块的内存需求。 可将所有内存请求委托给Python内存管理器也会使解释器整体上有更准确的内存占用空间。 所以在某些情况下,Python内存管理器可能会或可能不会触发适当的操作,如垃圾收集,内存压缩等。

python内存管理机制

python的内存管理管理机制: 引入计数,垃圾回收和内存池机制

首先明确  变量和对象  概念

 

 

 1. 变量,通过变量指针引用对象,变量指针指向具体对象的内存空间,取对象的值

2. 对象,类型已知,每个对象都包含一个头部信息(类型标识符和引用计数器)

第一、 引用计数

(1)一个对象会记录着引用自己的对象的个数,每增加一个引用,个数加一,每减少一个引用,个数减一
(2)查看引用对象个数的方法:导入sys模块,使用模块中的getrefcount(对象)方法,由于这里也是一个引用,故输出的结果多1
(3)增加引用个数的情况:1.对象被创建p = Person(),增加1;2.对象被引用p1 = p,增加1;3.对象被当作参数传入函数func(object),增加2,原因是函数中有两个属性在引用该对象;4.对象存储到容器对象中l = [p],增加1
(4)减少引用个数的情况:1.对象的别名被销毁del p,减少1;2.对象的别名被赋予其他对象,减少1;3.对象离开自己的作用域,如getrefcount(对象)方法,每次用完后,其对对象的那个引用就会被销毁,减少1;4.对象从容器对象中删除,或者容器对象被销毁,减少1
例如:

 

 

第二、垃圾回收

当python中的对象越来越多,占据越来越大的内存,启动垃圾回收(garbage collection),将没用的而对象清除。

原理

当python中某个对象的引用计数将为0时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾。

注意

1、垃圾回收时,Python不能进行其它的任务,频繁的垃圾回收将大大降低Python的工作效率;

2、Python只会在特定条件下,自动启动垃圾回收(垃圾对象少就没必要回收)

3、当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动。

分代回收

       Python将所有的对象分为0,1,2三代;

  所有的新建对象都是0代对象;

  当某一代对象经历过垃圾回收,依然存活,就被归入下一代对象。

第三、内存池机制

Python中有分为大内存和小内存:(256K为界限分大小内存)

1、大内存使用malloc进行分配

2、小内存使用内存池进行分配

3、Python的内存池(金字塔)

以上是关于python的内存管理机制的主要内容,如果未能解决你的问题,请参考以下文章

python的内存管理机制

Python中的内存管理机制

Python内存管理机制

python怎么进行内存管理的?

python内存管理机制

python内存管理机制