成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Memory Management and Circular References in Pytho

muddyway / 2335人閱讀

摘要:一般情況下,的垃圾收集器會被用于檢測上面這樣的循環(huán)引用,并刪除掉它們。你可以通過強制垃圾收集器運行,并檢查列表里有什么來驗證上述結(jié)論。

-- [since Python 3.4, circular references are handled much better](http://engineering.hearsaysocial.com/2013/06/16/circular-references-in-python/#comment-2882030670)

Nice post. Note that starting from Python 3.4, circular references are handled much better (docs imply it should be
rare that they are not collected -- but don"t give specifics about how to make that happen). For example the
example you give is no longer a problem in Python 3.5 (probably not in 3.4 either, but can"t test it right now).
前言

用像 Python, Ruby 這樣的解釋型語言編程很方便的一個方面就是,通常情況下,你可以避免處理內(nèi)存管理相關(guān)的事情。然而,有一個眾所周知的情況 Python 一定會有內(nèi)存泄漏,這就是當你在對象創(chuàng)建中聲明了一個循環(huán)引用,而且在類聲明中實現(xiàn)了一個自定義的 __del__ 解構(gòu)方法。例如,考慮如下例子:

One of the more convenient aspects of writing code in interpreted languages such as Python or Ruby is that you normally can avoid dealing with memory management. However, one known case where Python will definitely leak memory is when you declare circular references in your object declarations and implement a custom __del__ destructor method in one these classes. For instance, consider the following example:

class A(object):
    def __init__(self, b_instance):
      self.b = b_instance

class B(object):
    def __init__(self):
        self.a = A(self)
    def __del__(self):
        print "die"

def test():
    b = B()

test()

當函數(shù) test() 被調(diào)用時,它聲明了一個對象 B,在 B 的 __init__ 函數(shù)中,把自己當成變量傳給了 A,A 然后在 __init__ 函數(shù)中聲明了對 B 的引用,這就造成了一個循環(huán)引用。一般情況下,python 的垃圾收集器會被用于檢測上面這樣的循環(huán)引用,并刪除掉它們。然而,因為自定義的 ___del__ 方法,垃圾收集器會把這個循環(huán)引用相關(guān)對象標記為 “uncollectable”。從設(shè)計上說,垃圾收集器并不知道循環(huán)引用對象的銷毀順序,所以也就不會去處理它們。你可以通過強制垃圾收集器運行,并檢查 gc.garbage 列表里有什么來驗證上述結(jié)論。

When the function test() is invoked, it declares an instance of B, which passes itself to A, which then sets a reference to B, resulting in a circular reference. Normally Python"s garbage collector, which is used to detect these types of cyclic references, would remove it. However, because of the custom destructor (the __del__ method), it marks this item as "uncollectable". By design, it doesn"t know the order in which to destroy the objects, so leaves them alone (see Python"s garbage collection documentation for more background). You can verify this aspect by forcing the Python garbage collector to run and inspecting what is set inside the gc.garbage array:

import gc
gc.collect()
print gc.garbage
[<__main__.B object at 0x7f59f57c98d0>]

你可以通過 objgraph 庫可視化這些循環(huán)引用。

You can also see these circular references visually by using the objgraph library, which relies on Python"s gc module to inspect the references to your Python objects. Note that objgraph library also deliberately plots the the custom __del__ methods in a red circle to spotlight a possible issue.

為了避免循環(huán)引用,你通常需要使用 weak reference,向 python 解釋器聲明:如果剩余的引用屬于 weak reference,或者使用了 context manager 或 with 語法,那么內(nèi)存可以被垃圾收集器回收并用于重新聲明對象。

To avoid circular references, you usually need to use weak references, declaring to the interpreter that the memory can be reclaimed for an object if the remaining references are of these types, or to use context managers and the with statement (for an example of this latter approach, see how it was solved for the happybase library).

find_circular_references.py
# -*- encoding: utf-8 -*-
from __future__ import print_function

import gc
import traceback
import types
from tornado import web, ioloop, gen
from tornado.http1connection import HTTP1ServerConnection


def find_circular_references(garbage=None):
    """
    從 garbage 中尋找循環(huán)引用
    """
    def inner(level):
        """
        處理內(nèi)層的數(shù)據(jù)
        """
        for item in level:
            item_id = id(item)
            if item_id not in garbage_ids:
                continue
            if item_id in visited_ids:
                continue
            if item_id in stack_ids:
                candidate = stack[stack.index(item):]
                candidate.append(item)
                found.append(candidate)
                continue

            stack.append(item)
            stack_ids.add(item_id)
            inner(gc.get_referents(item))
            stack.pop()
            stack_ids.remove(item_id)
            visited_ids.add(item_id)

    ######### 開始初始化 ########

    # 獲取傳入的 garbage 或者通過 gc 模塊獲取 garbage 列表
    garbage = garbage or gc.garbage

    # 已經(jīng)找到的循環(huán)引用列表 type: list of list
    found = []

    # 存放 item 的堆
    stack = []

    # 存放 item_id 的 set
    stack_ids = set()

    # 保存 garbage 里每個對象的 id
    garbage_ids = set(map(id, garbage))

    # 保存 visited item 的 id
    visited_ids = set()

    ######## 初始化結(jié)束 ########

    # 進入遞歸函數(shù) inner
    inner(garbage)
    inner = None
    return found


class CollectHandler(web.RequestHandler):
    @gen.coroutine
    def get(self):
        # collect_result = None
        collect_result = gc.collect()
        garbage = gc.garbage
        # for i in garbage[:5]:
        #     print(gc.get_referents(i), "
")
        self.write("Collected: {}
".format(collect_result))
        self.write("Garbage: {}
".format(len(gc.garbage)))
        for circular in find_circular_references():
            print("
==========
 Circular 
==========")
            for item in circular:
                print("    ", repr(item))
            for item in circular:
                if isinstance(item, types.FrameType):
                    print("
Locals:", item.f_locals)
                    print("
Traceback:", repr(item))
                    traceback.print_stack(item)

class DummyHandler(web.RequestHandler):
    @gen.coroutine
    def get(self):
        self.write("ok
")
        self.finish()

application = web.Application([
    (r"/dummy/", DummyHandler),
    (r"/collect/", CollectHandler),
], debug=True)

if __name__ == "__main__":
    gc.disable()
    gc.collect()
    gc.set_debug(gc.DEBUG_STATS | gc.DEBUG_LEAK)
    print("GC disabled")

    print("Start on 8888")
    application.listen(8888)
    ioloop.IOLoop.current().start()

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/40677.html

相關(guān)文章

  • 〔SPRING FRAMEWORK〕Dependencies

    摘要:每個屬性參數(shù)構(gòu)造函數(shù)中值的類型都能夠被成字符串類型。對比上文給出的個代碼片段,可發(fā)現(xiàn)皆在用不同的方法進行元數(shù)據(jù)配置,并且被配置的具體對象是數(shù)據(jù)庫驅(qū)動。 @(SPRING FRAMEWORK) 〔4〕7.4 Dependencies 聲明: 斜體字:《官檔》原文 斜體加粗字:《官檔》原文的重點字、詞、句 正體字+前置〔〕:個人表述行為,如:〔總結(jié)〕、〔分析〕等 灰體字:生詞 粉體...

    MonoLog 評論0 收藏0
  • 【譯文】Node.js垃圾回收機制-基礎(chǔ)

    摘要:正好最近在學(xué)習(xí)的各種實現(xiàn)原理,在這里斗膽翻譯一篇垃圾回收機制原文鏈接。自動管理的機制中,通常都會包含垃圾回收機制。二垃圾回收機制的概念垃圾回收,是一種自動管理應(yīng)用程序所占內(nèi)存的機制,簡稱方便起見,本文均采用此簡寫。 最近關(guān)注了一個國外技術(shù)博客RisingStack里面有很多高質(zhì)量,且對新手也很friendly的文章。正好最近在學(xué)習(xí)Node.js的各種實現(xiàn)原理,在這里斗膽翻譯一篇Node...

    haobowd 評論0 收藏0
  • LogParser v0.8.0 發(fā)布:一個用于定期增量式解析 Scrapy 爬蟲日志的 Pytho

    摘要:開源安裝通過通過使用方法作為運行請先確保當前主機已經(jīng)安裝和啟動通過命令啟動訪問假設(shè)運行于端口訪問以獲取某個爬蟲任務(wù)的日志分析詳情配合實現(xiàn)爬蟲進度可視化詳見在代碼中使用 GitHub 開源 my8100 / logparser 安裝 通過 pip: pip install logparser 通過 git: git clone https://github.com/my8100/logp...

    Object 評論0 收藏0
  • JavaScript深入淺出第3課:什么是垃圾回收算法?

    摘要:摘要是如何回收內(nèi)存的深入淺出系列深入淺出第課箭頭函數(shù)中的究竟是什么鬼深入淺出第課函數(shù)是一等公民是什么意思呢深入淺出第課什么是垃圾回收算法最近垃圾回收這個話題非?;?,大家不能隨隨便便的扔垃圾了,還得先分類,這樣方便對垃圾進行回收再利用。 摘要: JS是如何回收內(nèi)存的? 《JavaScript深入淺出》系列: JavaScript深入淺出第1課:箭頭函數(shù)中的this究竟是什么鬼? Jav...

    AaronYuan 評論0 收藏0
  • [譯]JavaScript是如何工作的:內(nèi)存管理以及如何處理四種常見的內(nèi)存泄漏

    摘要:是如何工作的內(nèi)存管理以及如何處理四種常見的內(nèi)存泄漏原文譯者幾個禮拜之前我們開始一系列對于以及其本質(zhì)工作原理的深入挖掘我們認為通過了解的構(gòu)建方式以及它們是如何共同合作的,你就能夠?qū)懗龈玫拇a以及應(yīng)用。 JavaScript是如何工作的:內(nèi)存管理以及如何處理四種常見的內(nèi)存泄漏 原文:How JavaScript works: memory management + how to han...

    tianren124 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<