标签:可变 标记 ace 内存管理 垃圾 占用 耗资源 无法 技术
1)python动态类型:2)引用计数:在python中,每个对象都有存有指向该对象的引用总数,即引用计数
原理:每个对象维护一个 ob_ref 字段,用来记录该对象当前被引用的次数
每当新的引用指向该对象时,它的引用计数ob_ref加1
每当该对象的引用失效时计数ob_ref减1
一旦对象的引用计数为0,该对象可以被回收,对象占用的内存空间将被释放
缺点:需要额外的空间维护引用计数,这个问题是其次的-------最主要的问题是它不能解决对象的“循环引用”
获取引用计数:getrefcount()
当使用某个引用作为参数,传递给getrefcount()时,参数实际上创建了一个临时的引用。因此, getrefcount()所得到的结果,会比期望的多1。
增加引用计数:当一个对象A被另一个对象B引用时,A的计数会+1
减少引用计数:del删除或重新引用时,引用计数会变化(del只是删除引用)
循环引用:
x = []
y = []
x.append(y)
y.append(x)
对于上面相互引用的情况,如果不存在其他对象对他们的引用,这两个对象 所占用的内存也还是无法回收,从而导致内存泄漏
引用计数机制的优点:简单,实时性
引用计数机制的缺点:维护引用计数消耗资源;循环引用时无法回收
3)垃圾回收
回收原则:当python某个对象的引用计数降为0时,可被垃圾回收
gc机制:
GC作为现代编程语言的自动内存管理机制,专注于两件事
找到内存中无用的垃圾资源
清除这些垃圾并把内存让出来给其他对象使用
效率问题:垃圾回收时,Python不能进行其它的任务。频繁的垃圾回收将大大降低Python的工作效率。
当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的 次数。当两者的差值高于某个阈值时,垃圾回收才会启动。
三种情况触发垃圾回收:
调用gc.collect()
GC达到阈值时
程序退出时
分代回收:这一策略的基本假设是:存活时间越久的对象,越不可能在后面的程序中变成垃圾
Python将所有的对象分为0,1,2三代
所有的新建对象都是0代对象。
当某一代对象经历过垃圾回收,依然存活,那么它就被归入下一代对象
垃圾回收启动时,一定会扫描所有的0代对象
如果0代经过一定次数垃圾回收,那么就启动对0代和1代的扫描清理
当1代也经历了一定次数的垃圾回收后,那么会启动对0,1,2,即对所有对象进行扫描
标记清除机制:首先标记对象(垃圾检测),然后清除垃圾(垃圾回收)
主要用于解决循环引用
1.标记:活动(有被引用),非活动(可被删除)
2.清除:清除所有非活动对象
4)缓冲池
整数对象缓冲池:对于[-5,256] 这样的小整数,系统已经初始化好,可以直接拿来用。而对于其他的大整数,系统则提 前申请了一块内存空间,等需要的时候在这上面创建大整数对象。
[-5,256]它们的ip地址都是同一个,其他的不一样
字符串缓存:为了检验两个引用指向同一个对象,我们可以用is关键字。is用于判断两个引用所指的对象是否相同。 当触发缓存机制时,只是创造了新的引用,而不是对象本身。
字符串的intern机制:python对于短小的,只含有字母数字的字符串自动触发缓存机制。其他情况不会缓存。
5)深拷贝和浅拷贝
数字拷贝:
多个引用指向同一个对象,如果一个引用值发生变化,那么实际上是让这个引用指向一个新的引用, 并不影响其他的引用的指向。
字典拷贝:
字典浅拷贝:拷贝第一层数据(地址)
现在a,b的内存地址是不一样的,b只能拷贝到a的第一层地址
字典深拷贝:递归拷贝所有层数据
一般而言,除了copy.deepcopy,其他都是浅拷贝,除了一些推导式如:x = [ [] for i in range(3) ]这个是深~
ps:直接赋值不属于拷贝
数字和字符串、元组,不能改变对象本身,只能改变引用的指向,称为不可变数据对象
列表、字典、集合可以通过引用其元素,改变对象自身(in-place change)。这种对象类型,称为可 变数据对象
标签:可变 标记 ace 内存管理 垃圾 占用 耗资源 无法 技术
原文地址:https://blog.51cto.com/13603998/2507110