zoukankan      html  css  js  c++  java
  • python类与对象-如何在环状数据结构中管理内存

    如何在环状数据结构中管理内存

    问题举例

    在python中,垃圾回收器通过引用计数来回收垃圾对象,

    在某些环状数据结构(树,图...),存在对象间的循环引用,比如树的父节点引用子节点,

    子节点同时引用父节点。测试同时del掉引用父子节点,两个对象不能被立即回收。

    分析

    当一个对象引用计数为0,或者只剩下弱引用时,这个对象会被释放。

    类中有一个内置方法__del__,这个方法会在类对象释放时调用。

    来个栗子

    class A:
        def __del__(self):
            print("__del__")
    
    
    a1 = A()
    a2 = a1;

    说明:

    (1)A创建创建的对象有两个计数引用(a1和a2)

    (2)当我们通过python -i test.py加载并运行这个文件到交互解释器中,__del__方法并没有被调用

    (3)但是如果我们把a1, a2都指向别的对象时,A创建的对象引用计数为0,这时对象就会被释放

    如下

    class A:
        def __del__(self):
            print("__del__")
    
    
    a1 = A()
    a2 = a1;
    
    a1 = None
    a2 = None

    注意:

    这个时候可能有的朋友发现通过python test.py运行第一段代码时,__del__方法也会被调用,这是为什么呢?

    其实答案很简单,通过python test.py运行代码后相当于直接退出程序,当一个程序退出时,这个程序内的所有变量都会被释放。

    弱引用

    弱引用不增加引用计数,使用弱引用访问对象得到对象引用

    import weakref
    
    class A:
        def __del__(self):
            print("__del__")
    
    
    a1 = A()
    a2 = weakref.ref(a1)
    a3 = a2()
    print(a3 is a1) #True

    解决思路

    使用标准库weakref.ref,它可以创建一种能访问对象但是不增加引用计数的对象

    栗子

    有一个双向链表,有3个节点:1, 2, 3,变量head指向节点1,节点1右引用节点2,节点2右引用节点3,

    节点3左弱引用节点2,节点2左弱引用节点1,如图

    说明:当变量head指向None时,节点1对象被释放,节点1的右引用节点2被释放,节点2的右引用节点3被释放

    代码

    import weakref
    class Node:
        def __init__(self, data):
            self.data = data
            self._left = None
            self.right = None
    
        def add_right(self, node):
            self.right = node
            node._left = weakref.ref(self)
    
        @property
        def left(self):
            return self._left()
    
        def __str__(self):
            return 'Node:<%s>' % self.data
    
        def __del__(self):
            print('in __del__: delete %s' % self)
    
    def create_linklist(n):
        head = current = Node(1)
        for i in range(2, n + 1):
            node = Node(i)
            current.add_right(node)
            current = node
        return head
    
    head = create_linklist(1000)
    print(head.right, head.right.left)
    input()
    head = None
    
    import time
    for _ in range(1000):
        time.sleep(1)
        print('run...')
    input('wait...')

    参考资料:python3实用编程技巧进阶

  • 相关阅读:
    求数组中最小的k个数
    二叉树的四种遍历方法(C++)
    常见排序算法总结(C++)
    《剑指offer》第六十八题:树中两个结点的最低公共祖先
    《剑指offer》第六十七题:把字符串转换成整数
    《剑指offer》第六十六题:构建乘积数组
    《剑指offer》第六十五题:不用加减乘除做加法
    《剑指offer》第六十四题:求1+2+…+n
    《剑指offer》第六十三题:股票的最大利润
    《剑指offer》第六十二题:圆圈中最后剩下的数字
  • 原文地址:https://www.cnblogs.com/marton/p/10847809.html
Copyright © 2011-2022 走看看