PYTHON对象引用与垃圾回收

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lzy98/article/details/88819209

title: 对象引用与垃圾回收
copyright: true
top: 0
date: 2019-02-24 10:32:33
tags: 垃圾回收
categories: Python高阶笔记
permalink:
password:
keywords:
description: Python的核心,对象引用,可变性与垃圾回收机制。

这个世界很温柔,但它不喜欢我。

变量

Python作为静态语言,他的变量与其他语言的变量是不一样的。比如java中的变量你需要提前申明,定义数据类型,然后交给虚拟机执行。但是在python中的变量,本质上是一个指针,举个例子。

a = 1

python会做如下步骤:

  1. 在内存中申请一块内存空间存储一个int类型的对象
  2. 生成int类型的对象
  3. 最后把变量a指向数字1上面
  4. 可以把多个变量指向同一个对象

所以说,python中变量其实是一个指针,指向不同的对象。

is 与 ==

在深入类与对象-上中提起到is与==的区别:

这一开头就介绍了类的三大特性,类型(type),值(value),身份(id)

is:只要id相同,就返回True
==:只要value相同,就返回True

比如 1 == 1.0就返回True,1 is 1.0 就返回False。

注意了,这里变量都是不可变的类型,数字,字符串,浮点数都是不可变的(这里其实是python的小整形小字符串指向的都是同一个指针),所以使用is他们的id都是一样的,并且你定义一个类,实例化给a和b(不传入参数),他们的id也是一样的,如果实例化后传入参数,即使参数一样的,那他们的id也是不一样的。

但是对于list,set,dict这种可变的数据类型来说id也是不一样的。

垃圾回收

定义

python中的垃圾回收是以引用计数为主,标记-清除和分代收集为辅。

引用计数:python在内存中存储每个对象的引用计数,如果计数变成0,该对象就会消失,分配给该对象的内存就会释放出来。

标记-清除:一些容器对象,比如说list、dict、tuple、instance等可能会出现引用循环,对于这些循环,垃圾回收器会定时回收这些循环(对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边)。

分代收集:python把内存根据对象存活时间划分为三代,对象创建之后,垃圾回收器会分配它们所属的代。每个对象都会被分配一个代,而被分配更年轻的代是被优先处理的,因此越晚创建的对象越容易被回收。

讲解

python的垃圾回收算法是引用计数为主,举个例子:

a = 100
b = a

这里python做了两步:

  1. 在100这个对象上,会有一个计数器,因为定义变量a=100,那么计数器的数值为1
  2. 然后又让b指向了a,本质上是b的指针也指向了100,这个时候100这个对象的计数器的数值为2
  3. 也就是说目前100这个对象的有两个变量指向他,计数器值是2

一开始在dict中介绍过,删除字典的某一对键值使用 del dict[‘user’],那么删除其他变量也是一样的,使用del即可。这个时候删除a

del a

这个时候100的计数器的值为1了,但是这个时候python并没有对100回收,因为之后当计数器的数值为0的时候才会回收100,这个时候你del a后,使用print(b)是没问题的,因为这个时候100这个对象还没有完全清除。

在一开始的魔法函数中,有__del__这个魔法函数,你定义的类中使用这个魔法函数,当你的类实例化运行完成后,需要回收垃圾的时候,就会调用这个del魔法函数,做你想要完成的事情。

Python垃圾回收机制

内存池机制

Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。

1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。

2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。

3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

展开阅读全文

《“垃圾回收”之我见》

04-21

http://www.visual-graph.comrnrn我一直搞不懂为什么会出现垃圾回收这种技术。直到最近。rnrn以前我以为自己用标准的ActiveX接口编写的控件一定能够适应不同的编程语言,结果在不同的语言中却发生各种奇怪的现象。rnrn首先,为了让vb能够识别我的类库对象,我的属性类型不能是IDispatch的派生类,而必须是IDispatch,vb才能识别,这样我知道,vb原来是后期绑定,它只对Variant这种变体操作,在运行中解释执行!rnrn这样就让某些使用其它工具的程序员有点小小的不爽,因为必须对对象做一个强制转换才行。但这是一种宿命,没办法,组件开发商必须这么做才能通用,因此,使用组件的程序员就只好将就一下了,好在这也不是什么繁琐的事情,仅仅是有一点点小小的繁琐而已。rnrn有些标准接口,如BSTR(宽字符串)是一定要在ActiveX中创建的(SysAllocString),但你不能释放它,释放是调用者做的事情。所有的编程语言都懂得要用SysFreeString这个函数用来释放你分配的BSTR字符串。所以我们不用担心自己分配的内存会不会造成内存垃圾。rnrn但是,对象就没有这么幸运了!我在ActiveX中建立的对象接口,当它被其他编程语言引用的时候,各种编程语言就开始乱来了!rnrnVC和VB要简单一点,只要在它应用你的对象时,增加这个对象的引用计数(AddRef)就可以了,VC和VB会自动释放它,通过减少一个引用计数(Release)来完成匹配。rnrnDelphi呢?基本上也是这样的,之所以说基本上,是因为在某些特殊的地方它却不会自动减少一个引用计数。这种情况在你引出的对象是一个属性的时候有时候会发生,但我目前还没发现究竟是哪些特殊的情形!(vc里面没有属性的概念)rnrnC++Builder最糟,靠,它绝对不会在引用你的对象之后减少一个引用计数!所以,使用这种语言,引用ActiveX对象的时候,就会出现内存垃圾!rnrn我这里强烈建议使用C++Builder的程序员,当你使用别人的ActiveX控件访问它的对象的时候,你一定要看看内存有没有泄漏!我真的很怀疑!rnrn我的产品是一个ActiveX控件,它要被应用在不同的编程语言中,可是却在C++Builder和Delphi中出现了内存的麻烦,怎么办?rnrn为了对付这个头疼的问题,我决定迁就Microsoft,让我的ActiveX控件在VC和VB中间自如地使用,而不出现内存问题。虽然我的程序是用C++Builder开发的,但我还是觉得Microsoft的产品虽然比较笨,但它确实够标准。Borland为了让程序员高兴,接口中有很多实用化的简单的东西,但却不够标准,只有Borland自己的开发工具能够充分利用这种“非标准化”带来的特殊好处。rnrn于是,我只好在ActiveX编写中添加了自己的“垃圾回收”机制。rnC++Builder和Delphi不是不能自如地释放某些对象内存吗?rn我便把那些没有释放的内存管理起来(我的程序当然知道哪些对象还没释放),在某些时刻清理一遍。rnrn所幸运的是,由于我的对象特别特别小(每个对象最多只有8字节),这种清理工作,我放到了程序退出的时候进行,应该没有问题了。作为一个程序员,我真的无法容忍任何内存泄漏,哪怕只有几个字节!rnrn呜呼!Microsoft 的.net技术就是为了兼容各种不同的编程语言,所以我怀疑垃圾回收技术的出现就是因为不同公司的编程语言在接口方面出现不兼容问题,欲寻求解决办法而出现的!rnrn是不是这样?我也不敢肯定!rnrn其它内容,请登陆http://www.visual-graph.comrnrn 论坛

没有更多推荐了,返回首页