<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 調試內存泄漏 > 譯者:[OSGeo 中國](https://www.osgeo.cn/) 在Scrapy中,請求、響應和項目等對象的生命周期是有限的:它們被創建、使用一段時間,最后被銷毀。 從所有這些對象中,請求可能是生命周期最長的請求,因為它一直在調度程序隊列中等待,直到需要處理它為止。有關詳細信息,請參閱 [體系結構概述](architecture.html#topics-architecture) . 由于這些零碎的物體有(相當長的)壽命,總有在沒有正確釋放它們的情況下將它們累積到內存中的風險,從而導致所謂的“內存泄漏”。 為了幫助調試內存泄漏,scrapy提供了一種內置機制,用于跟蹤調用的對象引用 [trackref](#topics-leaks-trackrefs) ,您還可以使用第三方庫 [Guppy](#topics-leaks-guppy) 有關更高級的內存調試(請參閱下面的詳細信息)。兩種機制都必須從 [Telnet Console](telnetconsole.html#topics-telnetconsole) . ## 內存泄漏的常見原因 Scrapy開發人員傳遞請求中引用的對象(例如,使用 [`meta`](request-response.html#scrapy.http.Request.meta "scrapy.http.Request.meta") 屬性或請求回調函數),它有效地將這些引用對象的生存期限制為請求的生存期。到目前為止,這是導致零碎項目內存泄漏的最常見原因,對于新手來說,這是一個很難調試的原因。 在大型項目中, Spider 通常是由不同的人編寫的,其中一些 Spider 可能會“泄漏”,從而在其他(寫得好的) Spider 同時運行時影響其他 Spider ,而這反過來又會影響整個爬行過程。 如果您沒有正確地釋放(以前分配的)資源,那么泄漏也可能來自您編寫的定制中間件、管道或擴展。例如,在上分配資源 [`spider_opened`](signals.html#std:signal-spider_opened) 但不釋放它們 [`spider_closed`](signals.html#std:signal-spider_closed) 如果你跑步,可能會引起問題 [multiple spiders per process](practices.html#run-multiple-spiders) . ### 請求太多? 默認情況下,scrapy將請求隊列保存在內存中;它包括 [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") 對象和請求屬性中引用的所有對象(例如 [`meta`](request-response.html#scrapy.http.Request.meta "scrapy.http.Request.meta") )雖然不一定是泄漏,但這可能會占用大量內存。有可能 [persistent job queue](jobs.html#topics-jobs) 有助于控制內存使用。 ## 使用調試內存泄漏 `trackref` `trackref` 是Scrapy提供的一個模塊,用于調試最常見的內存泄漏情況。它基本上跟蹤對所有活動請求、響應、項和選擇器對象的引用。 您可以進入telnet控制臺并使用 `prefs()` 函數的別名 [`print_live_refs()`](#scrapy.utils.trackref.print_live_refs "scrapy.utils.trackref.print_live_refs") 功能: ```py telnet localhost 6023 >>> prefs() Live References ExampleSpider 1 oldest: 15s ago HtmlResponse 10 oldest: 1s ago Selector 2 oldest: 0s ago FormRequest 878 oldest: 7s ago ``` 如您所見,該報告還顯示了每個類中最舊對象的“年齡”。如果每個進程運行多個spider,那么通過查看最早的請求或響應,您很可能會發現哪個spider正在泄漏。您可以使用 [`get_oldest()`](#scrapy.utils.trackref.get_oldest "scrapy.utils.trackref.get_oldest") 功能(從telnet控制臺)。 ### 跟蹤哪些對象? 被跟蹤的對象 `trackrefs` 都來自這些類(及其所有子類): * [`scrapy.http.Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") * [`scrapy.http.Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") * [`scrapy.item.Item`](items.html#scrapy.item.Item "scrapy.item.Item") * [`scrapy.selector.Selector`](selectors.html#scrapy.selector.Selector "scrapy.selector.Selector") * [`scrapy.spiders.Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") ### 一個真實的例子 讓我們來看一個假設的內存泄漏案例的具體示例。假設我們有一只 Spider ,上面有一條和這條類似的線: ```py return Request("http://www.somenastyspider.com/product.php?pid=%d" % product_id, callback=self.parse, meta={referer: response}) ``` 該行正在請求中傳遞一個響應引用,它有效地將響應生命周期與請求的生命周期聯系起來,這肯定會導致內存泄漏。 讓我們看看如何通過使用 `trackref` 工具。 當爬蟲運行幾分鐘后,我們注意到它的內存使用量增長了很多,我們可以進入它的telnet控制臺并檢查實時引用: ```py >>> prefs() Live References SomenastySpider 1 oldest: 15s ago HtmlResponse 3890 oldest: 265s ago Selector 2 oldest: 0s ago Request 3878 oldest: 250s ago ``` 事實上,存在如此多的實時響應(而且它們太老了),這是絕對可疑的,因為與請求相比,響應的生存期應該相對較短。響應的數量與請求的數量相似,因此看起來它們是以某種方式捆綁在一起的。我們現在可以檢查 Spider 的代碼,以發現產生泄漏的討厭的行(在請求中傳遞響應引用)。 有時,關于活動對象的額外信息可能會有所幫助。讓我們檢查最早的響應: ```py >>> from scrapy.utils.trackref import get_oldest >>> r = get_oldest('HtmlResponse') >>> r.url 'http://www.somenastyspider.com/product.php?pid=123' ``` 如果您希望遍歷所有對象,而不是獲取最舊的對象,則可以使用 [`scrapy.utils.trackref.iter_all()`](#scrapy.utils.trackref.iter_all "scrapy.utils.trackref.iter_all") 功能: ```py >>> from scrapy.utils.trackref import iter_all >>> [r.url for r in iter_all('HtmlResponse')] ['http://www.somenastyspider.com/product.php?pid=123', 'http://www.somenastyspider.com/product.php?pid=584', ... ``` ### Spider 太多了? 如果項目并行執行的spider太多,則 `prefs()` 很難閱讀。因此,該函數具有 `ignore` 可用于忽略特定類(及其所有子類)的參數。例如,這不會顯示任何對 Spider 的實時引用: ```py >>> from scrapy.spiders import Spider >>> prefs(ignore=Spider) ``` ### scrapy.utils.trackRef模塊 以下是 [`trackref`](#module-scrapy.utils.trackref "scrapy.utils.trackref: Track references of live objects") 模塊。 ```py class scrapy.utils.trackref.object_ref ``` 如果要使用跟蹤活動實例,請從此類(而不是對象)繼承 `trackref` 模塊。 ```py scrapy.utils.trackref.print_live_refs(class_name, ignore=NoneType) ``` 打印實時引用的報告,按類名分組。 | 參數: | **ignore** (_class_ _or_ _classes tuple_) -- 如果給定,則將忽略指定類(或類的元組)中的所有對象。 | | --- | --- | ```py scrapy.utils.trackref.get_oldest(class_name) ``` 返回具有給定類名的最舊活動對象,或者 `None` 如果沒有找到。使用 [`print_live_refs()`](#scrapy.utils.trackref.print_live_refs "scrapy.utils.trackref.print_live_refs") 首先獲取每個類名的所有跟蹤活動對象的列表。 ```py scrapy.utils.trackref.iter_all(class_name) ``` 返回具有給定類名的所有活動對象的迭代器,或者 `None` 如果沒有找到。使用 [`print_live_refs()`](#scrapy.utils.trackref.print_live_refs "scrapy.utils.trackref.print_live_refs") 首先獲取每個類名的所有跟蹤活動對象的列表。 ## 用Guppy調試內存泄漏 `trackref` 為跟蹤內存泄漏提供了非常方便的機制,但它只跟蹤更可能導致內存泄漏的對象(請求、響應、項和選擇器)。但是,還有其他一些情況,內存泄漏可能來自其他(或多或少是模糊的)對象。如果這是你的情況,你不能用 `trackref` ,您還有另一個資源: [Guppy library](https://pypi.python.org/pypi/guppy). If you're using Python3, see [用muppy調試內存泄漏](#topics-leaks-muppy). 如果你使用 `pip` ,可以使用以下命令安裝Guppy:: ```py pip install guppy ``` telnet控制臺還提供內置的快捷方式( `hpy` )用于訪問Guppy堆對象。下面是一個使用guppy查看堆中所有可用python對象的示例: ```py >>> x = hpy.heap() >>> x.bytype Partition of a set of 297033 objects. Total size = 52587824 bytes. Index Count % Size % Cumulative % Type 0 22307 8 16423880 31 16423880 31 dict 1 122285 41 12441544 24 28865424 55 str 2 68346 23 5966696 11 34832120 66 tuple 3 227 0 5836528 11 40668648 77 unicode 4 2461 1 2222272 4 42890920 82 type 5 16870 6 2024400 4 44915320 85 function 6 13949 5 1673880 3 46589200 89 types.CodeType 7 13422 5 1653104 3 48242304 92 list 8 3735 1 1173680 2 49415984 94 _sre.SRE_Pattern 9 1209 0 456936 1 49872920 95 scrapy.http.headers.Headers <1676 more rows. Type e.g. '_.more' to view.> ``` 你可以看到大多數空間都是聽寫使用的。然后,如果要查看引用這些dict的屬性,可以執行以下操作: ```py >>> x.bytype[0].byvia Partition of a set of 22307 objects. Total size = 16423880 bytes. Index Count % Size % Cumulative % Referred Via: 0 10982 49 9416336 57 9416336 57 '.__dict__' 1 1820 8 2681504 16 12097840 74 '.__dict__', '.func_globals' 2 3097 14 1122904 7 13220744 80 3 990 4 277200 2 13497944 82 "['cookies']" 4 987 4 276360 2 13774304 84 "['cache']" 5 985 4 275800 2 14050104 86 "['meta']" 6 897 4 251160 2 14301264 87 '[2]' 7 1 0 196888 1 14498152 88 "['moduleDict']", "['modules']" 8 672 3 188160 1 14686312 89 "['cb_kwargs']" 9 27 0 155016 1 14841328 90 '[1]' <333 more rows. Type e.g. '_.more' to view.> ``` 正如您所看到的,Guppy模塊非常強大,但也需要對Python內部結構有一些深入的了解。有關Guppy的更多信息,請參閱 [Guppy documentation](http://guppy-pe.sourceforge.net/) . ## 用muppy調試內存泄漏 如果您使用的是python 3,那么可以使用muppy [Pympler](https://pypi.org/project/Pympler/) . 如果你使用 `pip` ,可以使用以下命令安裝muppy:: ```py pip install Pympler ``` 下面是一個使用muppy查看堆中所有可用python對象的示例: ```py >>> from pympler import muppy >>> all_objects = muppy.get_objects() >>> len(all_objects) 28667 >>> from pympler import summary >>> suml = summary.summarize(all_objects) >>> summary.print_(suml) types | # objects | total size ==================================== | =========== | ============ <class 'str | 9822 | 1.10 MB <class 'dict | 1658 | 856.62 KB <class 'type | 436 | 443.60 KB <class 'code | 2974 | 419.56 KB <class '_io.BufferedWriter | 2 | 256.34 KB <class 'set | 420 | 159.88 KB <class '_io.BufferedReader | 1 | 128.17 KB <class 'wrapper_descriptor | 1130 | 88.28 KB <class 'tuple | 1304 | 86.57 KB <class 'weakref | 1013 | 79.14 KB <class 'builtin_function_or_method | 958 | 67.36 KB <class 'method_descriptor | 865 | 60.82 KB <class 'abc.ABCMeta | 62 | 59.96 KB <class 'list | 446 | 58.52 KB <class 'int | 1425 | 43.20 KB ``` 有關Muppy的更多信息,請參閱 [muppy documentation](https://pythonhosted.org/Pympler/muppy.html) . ## 無泄漏泄漏 有時,您可能會注意到您的廢進程的內存使用只會增加,但不會減少。不幸的是,即使Scrapy和您的項目都沒有泄漏內存,也可能發生這種情況。這是由于Python的一個(不太常見)已知問題造成的,在某些情況下,該問題可能不會將釋放的內存返回到操作系統。有關此問題的詳細信息,請參閱: * [Python Memory Management](http://www.evanjones.ca/python-memory.html) * [Python Memory Management Part 2](http://www.evanjones.ca/python-memory-part2.html) * [Python Memory Management Part 3](http://www.evanjones.ca/python-memory-part3.html) Evan Jones提出的改進建議,詳情見 [this paper](http://www.evanjones.ca/memoryallocator/) 在python 2.5中進行了合并,但這只會減少問題,并不能完全解決問題。引用論文: > _不幸的是,這個補丁只能在競技場中不再分配對象的情況下釋放競技場。這意味著碎片化是一個大問題。一個應用程序可以有許多兆字節的空閑內存,分散在所有的區域中,但是它將無法釋放其中的任何一個。這是所有內存分配器都遇到的問題。解決這個問題的唯一方法是移動到一個壓縮垃圾收集器,它能夠移動內存中的對象。這需要對python解釋器進行重大更改。_ 為了保持內存消耗合理,可以將作業拆分為幾個較小的作業或啟用 [persistent job queue](jobs.html#topics-jobs) 不時停止/啟動Spider。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看