• Jingxiao 置顶
    2019-07-06
    思考题答案:

    事实上算法可以写的很简单,这是个很经典的 dfs (深度优先搜索)遍历,从起点开始遍历,对遍历到的节点做个记号。遍历完成后,再对所有节点扫一遍,没有被做记号的,就是需要垃圾回收的。
    
     8
  • Switch
    2019-07-08
    思考题:
    from typing import Set


    class Graph:
        def __init__(self, value, nodes=None):
            self._value = value
            self._nodes: list = [] if nodes is None else nodes

        @property
        def value(self):
            return self._value

        @property
        def nodes(self):
            return self._nodes

        def node_add(self, node):
            self._nodes.append(node)

        def node_adds(self, nodes):
            self._nodes.extend(nodes)

        def node_del(self, node):
            self._nodes.remove(node)

        def __str__(self):
            return "Graph {} nodes {}".format(self._value, [node.value for node in self.nodes])

        def __repr__(self):
            return self.__str__()


    def dfs(start: Graph, includes: Set[Graph] = None) -> Set[Graph]:
        if includes is None:
            includes = set()
        if start in includes:
            return includes
        includes.add(start)
        for s in start.nodes:
            includes.update(dfs(s, includes))
        return includes


    if __name__ == '__main__':
        A = Graph('A')
        B = Graph('B')
        C = Graph('C')
        D = Graph('D')
        E = Graph('E')
        F = Graph('F')
        has_nodes = {A, B, C, D, E, F}

        # A->B->E
        # ->C->E
        # B->A
        # D->F
        # F->D
        A.node_adds([B, C])
        B.node_adds([A, E])
        C.node_adds([E])
        D.node_adds([F])
        F.node_adds([D])
        graph_nodes = dfs(A, set())
        # OUT: {Graph B nodes ['A', 'E'], Graph E nodes [], Graph C nodes ['E'], Graph A nodes ['B', 'C']}
        print(graph_nodes)
        # OUT: {Graph F nodes ['D'], Graph D nodes ['F']}
        print(has_nodes - graph_nodes)
    展开
     1
     12
  • 程序员人生
    2019-07-03
    请问一下,老师
    执行关于objgraph代码,出现如下错误:
    Graph viewer (xdot) and image renderer (dot) not found, not doing anything else
    是不是还要安装什么软件?
     6
     4
  • 陈迪🐶
    2019-07-03
    1. 循环引用情况下Python不立即回收内存,如果放任不管,即不显式调用gc.collect的话,Python的垃圾回收器自己会什么时候处理?
    2. 最后介绍了内存泄露排查工具,哪种算内存泄露呢?接问题1,不立即回收算内存泄露吗?还是有其他场景

    作者回复: 分代收集算法中每一代都有一个默认阈值,超过指定阈值之后就会启动垃圾回收。如果垃圾回收启动太频繁,会造成程序性能低下,分代收集也是为了提高性能,因此不立刻回收没关系,只要一定时间或者一定阈值之后回收都没问题。内存泄漏是这部分内存永远不再被回收,越攒越多,直到撑爆内存。

     2
     2
  • 天凉好个秋
    2019-07-03
    本文讲的垃圾回收算法在Java中也都有,当初在设计的时候是不是参考了Java?而且,Java中还有标记整理算法,可以解决回收内存不连续的问题,这个在Python中有没有考虑呢?

    作者回复: 程序语言设计的时候肯定会有互相参考,Java 中的 gc 就很丰富了,程序员可以根据需要配置适合自己应用的 gc 算法,甚至在 OpenJDK 开源后,可以在更深的层次上对本来不对用户开放的细节进行深入配置。python 则并不希望编写者们对这里有过深入了解,拿来开箱即用就行了,这也是 python 设计哲学的一部分,牺牲一定性能换取方便性。

     1
     2
  •   星豪
    2019-07-04
    1. 在读文章的时候找了一个可能是错别字的地方,在循环引用那一节中,第四段试想一下,如果这段代码出现在生产环境中...但经过长时间运行“候”...。这一侯应该是后来的后吧?
    2. 当垃圾回收器中新增对象减去删除对象达到相应的阈值时,就会对这一代对象启动垃圾回收。这一句话不是很明白,新增对象我理解的是新创建的对象或者是从上一代挪过来的对象,那么删除对象指的是哪些呢?或者说是如何进行指定哪些是应该被删除的对象呢?

    作者回复: 1. 谢谢
    2. 新增对象指代你创建一个对象,删除对象指代对象被释放,例如手动调用 del,从函数中返回临时变量的释放等,对这两者进行计数统计,然后相减。

    
     1
  • 瞌睡的咸鱼
    2019-07-03
    思考题——通过有向图的拓扑排序可以求出(可以参考《算法导论》去理解)
    
     1
  • 干布球
    2019-07-03
    请问老师,问什么多次调用print(sys.getrefcount(a)),只有第一次会增加a的计数呢?
     2
     1
  • 微风漂过
    2020-01-31
    开头的代码
    运行出错:ModuleNotFoundError: No module named 'psutil'
    安装出错:
    pip install --upgrade psutil
    Collecting psutil
      Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='pypi.org', port=443): Read timed out. (read timeout=15)")': /simple/psutil/
      Could not find a version that satisfies the requirement psutil (from versions: )
    No matching distribution found for psutil
    请问这是什么原因?
    展开
    
    
  • wnz27
    2019-12-03
    gc.collect(),不是清除没有引用的对象吗,为什么循环引用代码里没有del a和del b可以垃圾回收呢?是老师手误吗?
    
    
  • 建强
    2019-11-02
    简单写了一个有向图的遍历程序,说明:
    (1)有向图采用邻接链表存储
    (2)有向图采用递归算法进行深度优先遍历
    #邻接链表节点定义
    class LinkNode:
        def __init__(self,data):
            self.data = data
            self.next = None
        
    #邻接链表定义
    class AdjoinList:
        def __init__(self):
            self.adjlist = {} #存贮节点间的邻接关系
            self.vistlist = {} #存贮节点是否被访问,初始所有节点都是False
        
        #建立结点x1和x2的连接关系,其中,x1指向x2
        def addNode(self,x1,x2):

            #建立链接
            point = self.adjlist.setdefault(x1, None)
            lnode = LinkNode(x2)
            lnode.next = point
            self.adjlist[x1] = lnode
            self.adjlist.setdefault(x2, None)

            #初始化访问列表
            self.vistlist.setdefault(x1,False)
            self.vistlist.setdefault(x2,False)

        #遍历图中所有结点
        def visitNode(self,nodevalue):
            if nodevalue is not None:
                self.vistlist[nodevalue] = True
                print('visist:', nodevalue)
                nextnode = self.adjlist[nodevalue]
                    
                while nextnode is not None:

                    if not self.vistlist[nextnode.data]:
                        self.visitNode(nextnode.data)
                    
                    nextnode = nextnode.next


        #输出未被访问的结点
        def showUnvistedNode(self):
            print('UnvistedNode:', ','.join([x for x in self.vistlist if not self.vistlist[x]]))

    #主程序
    def main():
    #BEGIN

        adlist = AdjoinList()

        #创建有向图,有向图简单示意如下:
        '''
        a-->b-->c
        |
        |
        d-->e-->f

        g-->h-->j
        
        '''
        adlist.addNode('a','b')
        adlist.addNode('a','d')
        adlist.addNode('b','c')
        adlist.addNode('d','e')
        adlist.addNode('e','f')
        adlist.addNode('g','h')
        adlist.addNode('h','j')

        #从a节点开始遍历有向图
        adlist.visitNode('a')

        #输出未访问的节点
        adlist.showUnvistedNode()

    #END

    if __name__ == '__main__':
        main()
    展开
    
    
  • 自由民
    2019-10-17
    思考题,就是图的遍历算法,深度优先或广度优先算法,标记每个节点,遍历后,没标记过的就是可以回收的垃圾。
    
    
  • 夏尔
    2019-09-06
    def func():
        show_memory_info('initial')
        a = [i for i in derange(10000000)]
        show_memory_info('after a created')
        return a

    a = func()
    show_memory_info('finished')

    ########## 输出 ##########

    initial memory used: 47.96484375 MB
    after a created memory used: 434.515625 MB
    finished memory used: 434.515625 MB

    这是本文第四个代码块,for i in range;多了de,变成了derange;
    展开
    
    
  • 小侠龙旋风
    2019-07-07
    老师,请问:除了循环引用,还有哪些错误的程序设计会造成内存泄漏,需要强制调用gc.collect()来垃圾回收?
    
    
  • 陈迪🐶
    2019-07-06
    可否给一个内存泄露的实例,逃脱了gc的“法眼”?
    
    
  • KaitoShy
    2019-07-04
    请问一下,老师:
    import sys

    a= [1]

    print(sys.getrefcount(a))

    b = a
    print(sys.getrefcount(a))

    c,d,e,f,g,h = b,b,c,e,d,a
    print(g)
    print(sys.getrefcount(a))
    -------


    import sys...
    2
    3
    [1]
    6
    为什么最后一次是6次?而g的值是正常的呢?
    展开
     1
    
  • 响雨
    2019-07-03
    思考题看的我一脸蒙蔽,无从下手
    
    
  • 舒服
    2019-07-03
    什么是函数调用栈
    
    
  • ikimiy
    2019-07-03
    python的垃圾回收相对于Java来说是不是简单很多,Java 的垃圾回收好像不再使用引用计数了是吗?Java 有很多种垃圾收集器,比如G1,CMS等,python的垃圾收集器也分很多种的么!
     1
    
我们在线,来聊聊吧