变量与对象

注 1:变量名没有类型,类型属于对象(因为变量引用对象,所以类型随对象),变量引用什么类型的对象,变量就是什么类型

var1 = "hello world"
var2 = var1
id(var1)
id(var2)

注 2:id() 是 python 的内置函数,用于返回对象的身份,即对象的内存地址

# 短字符串
a = "hello"
b = "hello"
print(a is b)          # True

# 整数
a = 12
b = 12
print(a is b)      # True

# 长字符串
a = "id()是python的内置函数,用于返回对象的身份,即对象的内存地址"
b = "id()是python的内置函数,用于返回对象的身份,即对象的内存地址"
print(a is b)      # False

注 3:is 是用来判断两个引用所指的对象是否相同,==是用来判断两个变量对应的值是否相同

由运行结果可知:
1、python 缓存了整数和短字符串,因此每个对象在内存中只存在一份,引用所指对象就是相同的,即使使用赋值语句,也只是创造新的引用,而不是对象本身
2、python 没有缓存长字符串、列表以及其他对象,可以由多个相同的对象,使用赋值语句创建新的对象
3、python 中对大于 256 的整数,会重新分配对象空间地址保存对象;对于字符串来说,如果不包含空格的字符串,则不会重新分配对象空间,对于包含空格的字符串则会重新分配

引用计数

python 中 每个对象都有指向该对象的引用总数 -- 引用计数
查看对象的引用次数:sys.getrefcount()

import sys

a = [1, 2, 3]
sys.getrefcount(a)      # 2
b = a
sys.getrefcount(a)      # 3
sys.getrefcount(b)      # 3

注 4:当使用某个引用作为参数,传递给 getrefcount() 时,参数实际上创建了一个临时的引用,因此,getrefcount() 所得到的结果,会比期望的多 1

python 的一个容器对象(列表、字典、集合等),可以保护多个对象,实际上,容器对象中包含的并不是元素对象本身,而是指向各个元素对象的引用

垃圾回收

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

a = [123]
del a

注 5:
1、垃圾回收时,python 不能进行其他的任务,频繁的垃圾回收将大大降低 python 的工作效率
2、python 只会在特定条件下,自动启动垃圾回收(垃圾对象少就没必要回收)
3、当 python 运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallccation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动

import gc

gc.get_threshold()          # (700, 10, 10)

阈值分析:

标记清除

如果两个对象的引用计数都为 1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的。也就是说,它们的引用计数虽然表现为非 0,但实际上有效的引用计数为 0,所有先将循环引用摘掉,就会得出这两个对象的有效计数

总结

1、python 使用引用计数和垃圾回收来释放 python 对象的内存
2、引用计数的优点是原理简单,但是会增加 python 运行时间;缺点是无法处理循环引用
3、python 标记清除用于处理循环引用
4、gc module 是 python 垃圾回收机制的接口模块,可以通过该模块启停垃圾回收、调整回收触发的阈值

以上内容摘自:https://blog.csdn.net/weixin_39653717/article/details/110371108


↙↙↙阅读原文可查看相关链接,并与作者交流