28

内存中的Python:Python引用计数指南

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzI2NjkyNDQ3Mw%3D%3D&%3Bmid=2247493358&%3Bidx=2&%3Bsn=3b28e7498489d1ebf83971a03b7dfe3b
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

EjyQZvZ.jpg!web

全文共 1372 字,预计学习时长 7 分钟

MfaEvqA.jpg!web

图源:unsplash  

本文将会为你介绍Python引用计数,演示中使用可变列表对象,不过本文不介绍C语言实现细节。

需要注意的是,代码段的输出在硬件上可能有所不同。

变量是内存引用

Python中的变量是内存引用。如果输入x = [1,2]时会发生什么?[1,2]是对象。

回想一下,一切都是Python中的对象。[1,2]将在内存中创建。x是[1,2]对象的内存引用。

来看看下面的例子。可以找到x所引用的内存地址。请务必只使用id(x),它会以10为基数,而十六进制函数会将其转换为十六进制。

<span>x = [1, 2]</span>

<span> print(hex(id(x))) <span># output: 0x32ebea8</span></span>

M7raAvQ.png!web

引用计数

现在已经在内存中创建了一个list对象,而且x对该对象进行了引用。那么y=[1,2]和y=x有什么区别?

当输入y=[1,2]时,它将在内存中创建一个新的list对象,并且y将引用它。

x = [1, 2]
   y = [1, 2]
   print(hex(id(x)))  # output: 0x101bea8
   print(hex(id(y)))  # output: 0x31a5528

而当输入y=x时,等同于告诉Python希望y 变量引用x变量引用的内容。因为变量是内存引用的。

可以确认x和y引用同一个对象。

x = [1, 2]
   y = x
   print(hex(id(x)))  # output: 0x74bea8
   print(hex(id(y)))  # output: 0x74bea8

3yAvMfy.png!web

引用计数的数目

接下来的问题是,有多少变量引用同一个对象?

错误的用法:

我看到有些人在使用sys.getrefcount(var)时不知道如何传递var,而是向对象添加引用。一起看看下面的例子。

输出3,而期望的却是2(x andy)。发生这种情况是因为将x传递给getrefcount函数时又添加了一个引用。

from sys import getrefcount
          x = [1, 2]
          y = x
          print(hex(id(x)))  # output: 0xb65748
          print(hex(id(y)))  # output: 0xb65748
          print(getrefcount(x))  # output: 3

更好的用法:

可以使用内置的ctypes模块来找到预期的结果。必须将x的id传递给from_address函数。

from ctypes import c_long
      x = [1, 2]
      y = x
      print(hex(id(x)))  # output: 0x3395748
      print(hex(id(y)))  # output: 0x3395748
      print(c_long.from_address(id(x)).value)  # output: 2

概言之,错误的用法是传递变量,而更好的用法则是传递变量的id,这意味着只传递基数为10的数字,而不是变量。

当对象消失时

RZbmEfJ.jpg!web

图源:unsplash  

当没有变量引用对象时会发生什么?

对象将从内存中删除,因为没有引用该对象的内容。不过也有例外:如果有循环引用,garbage collector 将开始奏效。

为什么使用可变对象

不可变对象由于性能原因,结果可能与预期不同。查看下面的例子,观察输出是如何变化的。

import sys
      import ctypes
             """Some Mutable Objects """
      a =list()
      b =set()
      c =dict()
      d =bytearray()
      """ Some ImmutableObjects """
      e =tuple()
      f =int()
      g =str()
      print(sys.getrefcount(a),ctypes.c_long.from_address(id(a)).value)  # output: 2 1
      print(sys.getrefcount(b),ctypes.c_long.from_address(id(b)).value)  # output: 2 1
      print(sys.getrefcount(c),ctypes.c_long.from_address(id(c)).value)  # output: 2 1
      print(sys.getrefcount(d),ctypes.c_long.from_address(id(d)).value)  # output: 2 1
      print(sys.getrefcount(e),ctypes.c_long.from_address(id(e)).value)  # output: 1298 1297
      print(sys.getrefcount(f),ctypes.c_long.from_address(id(f)).value)  # output: 209 208
      print(sys.getrefcount(g),ctypes.c_long.from_address(id(g)).value)  # output: 59 58

2iUJRbz.png!web

图源:Unsplash

文中所谈及的一切都对CPython有效。希望对你有帮助。

VbeE7j3.jpg!web

推荐阅读专题

NBJ7vyI.jpg!web

bEniumQ.jpg!web

m6jER3M.jpg!web

iuUFJbn.jpg!web

Nbqmy26.jpg!web

留言点赞发个朋友圈

我们一起分享AI学习与发展的干货

编译组:陈枫、王品一

相关链接:

https://medium.com/better-programming/a-guide-to-reference-counting-in-python-27334fc2e3c1

如转载,请后台留言,遵守转载规范

推荐文章阅读


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK