美文网首页
Python对象引用、可变性和垃圾回收

Python对象引用、可变性和垃圾回收

作者: 马本不想再等了 | 来源:发表于2019-02-23 19:47 被阅读0次

    1. Python中的变量是什么

    Python和Java中的变量不一样,Python的变量实质上是一个指针
    例如:a = 1 a = "abc"可以理解为先生成1或者abc,然后再把a指向这个对象,a本身没有类型,这也即是Python不需要声明类型的原理。
    也可以形象的将python中的变量看做一个便利贴,是指给已生成的对象进行贴上标记而已。

    a = [1,2,3]
    b = a
    print(id(a), id(b))
    b.append(4)
    print(a)
    >>> 39658440 36958440
    >>> 1 2 3 4
    # 这里a和b的地址一样,两张便利贴贴在同一个对象上。
    # 操作b所指向的对象之后,a指向的对象也发生了变化。
    

    2. == 与 is 的区别

    a和b指向不同的对象,它们的id也不想等,但是Python有一个intern机制,对于小整数、小字符等会临时分配同样的地址,其本质是一种优化。
    a == b之所以成立的原因是,在list内置一个eq的方法,会默认取出对象中的值进行对比。

    a = [1,2,3,4]
    b = [1,2,3,4]
    print(a == b)
    print(a is b)
    print(id(a), id(b))
    >>> True
    >>> False
    >>> 39724040 39724616
    

    3. 垃圾回收机制和del语句

    Python中的垃圾回收是以“引用计数”为主,“标记清除”和“分代回收”为辅。
    【引用计数】
    Python默认的垃圾收集机制是“引用计数”。每个对象维护了一个ob_ref引用计数字段,当新的引用指向该对象时,引用计数加1,当一个对象的引用被销毁时减1。一旦对象的引用计数为0,该对象立即被回收,所占用的内存将被释放。
    实例:

    a = object()
    b = a
    del a
    print(b)
    print(a)
    >>> <object object at 0x00000000003D90F0>
    >>> NameError:name 'a' is not defind
    # 当a,b都指向object()时,object()的计数为2,删除a时,计数为1。当计数为0时,其内存就会被释放。
    
    class A:
      def __del__(self):
        pass
    # 类中会有一个del方法,一般在垃圾回收时被调用
    

    【标记清除】
    标记——清除(Mark——Sweep)是一种基于追踪回收技术实现的垃圾回收算法。对象之间通过引用指针连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象出发,沿着有向边遍历对象,可达的对象标记为有用的对象,不可达的对象就是要被清除的对象。标记清除算法作为Python的辅助垃圾收集技术主要处理的是一些容器对象,比如list、dict、tuple,instance等,因为对于字符串、数值对象不可能造成循环引用问题。Python使用一个双向链表将这些容器对象组织起来。
    【分代回收】
    Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率随着对象的存活时间的增大而减小。新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾回收机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。

    4. 一个经典的参数错误

    def add(a, b):
      a += b
      return a
    # 为方便演示,以下为伪代码
    if __name__ == "__main__":
      a = 1
      b = 2
      c = add(a, b)
      print(c)
    >>> 3
    >>> 1 2
    
      a = [1,2]
      b = [3,4]
      c = add(a, b)
      print(c)
    >>> [1,2]
    >>> [1,2,3,4]  [3,4]
    
      a = (1, 2)
      b = (1, 2)
      c = add(a, b)
      print(c)
    >>> (1, 2)
    >>> (1, 2)  (3, 4)
    

    出现以上情况是因为list是可变对象,容易被修改。

    相关文章

      网友评论

          本文标题:Python对象引用、可变性和垃圾回收

          本文链接:https://www.haomeiwen.com/subject/spzpyqtx.html