zoukankan      html  css  js  c++  java
  • python的垃圾回收机制

    刚学面向对象被__del__函数搞的迷迷糊糊的,对垃圾回收的过程还有引用对象对垃圾回收的影响一直不是很清楚,然后看了博主Kevin Lu的博客觉得恍然大悟,现将部分文章复制过来供大家参考

     

    一.垃圾回收机制

    Python中的垃圾回收是以引用计数为主,分代收集为辅。引用计数的缺陷是循环引用的问题。
    在Python中,如果一个对象的引用数为0,Python虚拟机就会回收这个对象的内存。

    #encoding=utf-8
    __author__ = 'kevinlu1010@qq.com'
    
    class ClassA():
        def __init__(self):
            print 'object born,id:%s'%str(hex(id(self)))
        def __del__(self):
            print 'object del,id:%s'%str(hex(id(self)))
    
    def f1():
        while True:
            c1=ClassA()
            del c1

    执行f1()会循环输出这样的结果,而且进程占用的内存基本不会变动

    object born,id:0x237cf58
    object del,id:0x237cf58

    c1=ClassA()会创建一个对象,放在0x237cf58内存中,c1变量指向这个内存,这时候这个内存的引用计数是1
    del c1后,c1变量不再指向0x237cf58内存,所以这块内存的引用计数减一,等于0,所以就销毁了这个对象,然后释放内存。

    1. 导致引用计数+1的情况
      1. 对象被创建,例如a=23
      2. 对象被引用,例如b=a
      3. 对象被作为参数,传入到一个函数中,例如func(a)
      4. 对象作为一个元素,存储在容器中,例如list1=[a,a]
    2. 导致引用计数-1的情况
      1. 对象的别名被显式销毁,例如del a
      2. 对象的别名被赋予新的对象,例如a=24
      3. 一个对象离开它的作用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会)
      4. 对象所在的容器被销毁,或从容器中删除对象

      demo

      def func(c,d):
          print 'in func function', sys.getrefcount(c) - 1
      
      
      print 'init', sys.getrefcount(11) - 1
      a = 11
      print 'after a=11', sys.getrefcount(11) - 1
      b = a
      print 'after b=1', sys.getrefcount(11) - 1
      func(11)
      print 'after func(a)', sys.getrefcount(11) - 1
      list1 = [a, 12, 14]
      print 'after list1=[a,12,14]', sys.getrefcount(11) - 1
      a=12
      print 'after a=12', sys.getrefcount(11) - 1
      del a
      print 'after del a', sys.getrefcount(11) - 1
      del b
      print 'after del b', sys.getrefcount(11) - 1
      # list1.pop(0)
      # print 'after pop list1',sys.getrefcount(11)-1
      del list1
      print 'after del list1', sys.getrefcount(11) - 1

      输出:

      init 24
      after a=11 25
      after b=1 26
      in func function 28
      after func(a) 26
      after list1=[a,12,14] 27
      after a=12 26
      after del a 26
      after del b 25
      after del list1 24

      问题:为什么调用函数会令引用计数+2

    3. 查看一个对象的引用计数

    sys.getrefcount(a)可以查看a对象的引用计数,但是比正常计数大1,因为调用函数的时候传入a,这会让a的引用计数+1

    二.循环引用导致内存泄露

    def f2():
        while True:
            c1=ClassA()
            c2=ClassA()
            c1.t=c2
            c2.t=c1
            del c1
            del c2
            

    执行f2(),进程占用的内存会不断增大。

    object born,id:0x237cf30
    object born,id:0x237cf58

    创建了c1,c2后,0x237cf30(c1对应的内存,记为内存1),0x237cf58(c2对应的内存,记为内存2)这两块内存的引用计数都是1,执行c1.t=c2c2.t=c1后,这两块内存的引用计数变成2.
    在del c1后,内存1的对象的引用计数变为1,由于不是为0,所以内存1的对象不会被销毁,所以内存2的对象的引用数依然是2,在del c2后,同理,内存1的对象,内存2的对象的引用数都是1。
    虽然它们两个的对象都是可以被销毁的,但是由于循环引用,导致垃圾回收器都不会回收它们,所以就会导致内存泄露。

    原博客网址:http://www.cnblogs.com/Xjng/p/5128269.html

  • 相关阅读:
    检查宿舍卫生
    代码优化中 主窗口 问题 解决
    授权 存储
    升级Xcode7&iOS9后,出现NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -980X)
    控制器里面添加控制器
    版本新特性
    ios图片适配问题
    启动图片调整
    luogu_1896【题解】状压DP
    luogu_2602【题解】数位DP 数字计数
  • 原文地址:https://www.cnblogs.com/xisheng/p/7339818.html
Copyright © 2011-2022 走看看