本文转载自公众号《阅读核心》(ID:AI_Discovery)本文将向您介绍Python引用计数,在演示中使用变量列表对象,但本文确实不介绍C语言实现细节。请务必注意,代码片段的输出可能因硬件而异。变量是内存引用Python中的变量是内存引用。如果你输入x=[1,2]会发生什么?[1,2]是对象。回想一下,在Python中一切皆对象。[1,2]将在内存中创建。x是对[1,2]对象的内存引用。看看下面的例子。可以找到x引用的内存地址。确保只使用id(x),它将以10为底,十六进制函数会将其转换为十六进制。x=[1,2]print(hex(id(x)))#output:0x32ebea8引用计数现在已经在内存中创建了一个列表对象,x拥有对该对象的引用。那么y=[1,2]和y=x有什么区别呢?当输入y=[1,2]时,会在内存中新建一个list对象,y会引用它。x=[1,2]y=[1,2]print(hex(id(x)))#output:0x101bea8print(hex(id(y)))#output:0x31a5528当输入y=x时,就是相当于告诉Python你希望y变量引用x变量所指的内容。因为变量是在内存中引用的。可以确认x和y指的是同一个对象。x=[1,2]y=xprint(hex(id(x)))#output:0x74bea8print(hex(id(y)))#output:0x74bea8引用计数的数量接下来的问题是,有多少个变量引用相同目的?错误用法:我看到有些人在使用sys.getrefcount(var)时不知道如何传递var,而是添加对对象的引用。看看下面的例子。输出为3,但期望为2(xandy)。发生这种情况是因为在将x传递给getrefcount函数时添加了一个引用。fromsysimportgetrefcountx=[1,2]y=xprint(hex(id(x)))#output:0xb65748print(hex(id(y)))#output:0xb65748print(getrefcount(x))#output:3更好的用法:可以使用内置的ctypes模块找到预期结果。x的id必须传递给from_address函数。fromctypesimportc_longx=[1,2]y=xprint(hex(id(x)))#output:0x3395748print(hex(id(y)))#output:0x3395748print(c_long.from_address(id(x)).value)#output:2综上所述,错误的用法是传递变量,更好的用法是传递变量的id,也就是只传递10进制数,不传递变量。当对象消失时没有变量引用该对象会发生什么?该对象将从内存中删除,因为没有对该对象内容的引用。但也有例外:如果存在循环引用,垃圾收集器将启动。为什么使用可变对象不可变对象由于性能原因,结果可能与预期不同。查看下面的示例,了解输出如何变化。importsysimportctypes"""SomeMutableObjects"""a=list()b=set()c=dict()d=bytearray()"""SomeImmutableObjects"""e=tuple()f=int()g=str()打印(sys.getrefcount(a),ctypes.c_long.from_address(id(a)).value)#output:21print(sys.getrefcount(b),ctypes.c_long.from_address(id(b)).value)#输出:21print(sys.getrefcount(c),ctypes.c_long.from_address(id(c)).value)#output:21print(sys.getrefcount(d),ctypes.c_long.from_address(id(d)).value)#output:21print(sys.getrefcount(e),ctypes.c_long.from_address(id(e)).value)#output:12981297print(sys.getrefcount(f),ctypes.c_long.from_address(id(f)).value)#output:209208print(sys.getrefcount(g),ctypes.c_long.from_address(id(g)).value)#output:5958文中所谈及的一切都对CPython有效。希望对你有帮助。
