scrapy 2.3 使用調(diào)試內(nèi)存泄漏 trackref

2021-06-17 11:56 更新

?trackref? 是Scrapy提供的一個模塊,用于調(diào)試最常見的內(nèi)存泄漏情況。它基本上跟蹤對所有實(shí)時請求、響應(yīng)、項(xiàng)、蜘蛛和選擇器對象的引用。

您可以進(jìn)入telnet控制臺并使用 ?prefs()? 函數(shù)的別名 ?print_live_refs()? 功能:

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

如您所見,該報告還顯示了每個類中最舊對象的“年齡”。如果每個進(jìn)程運(yùn)行多個spider,那么通過查看最早的請求或響應(yīng),您很可能會發(fā)現(xiàn)哪個spider正在泄漏。您可以使用 ?get_oldest()? 功能(從telnet控制臺)。

跟蹤哪些對象?

被跟蹤的對象 ?trackrefs? 都來自這些類(及其所有子類):

  • ?scrapy.http.Request?
  • ?scrapy.http.Response?
  • ?scrapy.item.Item?
  • ?scrapy.selector.Selector?
  • ?scrapy.spiders.Spider?

一個真實(shí)的例子

讓我們來看一個假設(shè)的內(nèi)存泄漏案例的具體示例。假設(shè)我們有一只蜘蛛,上面有一條和這條類似的線:

return Request(f"http://www.somenastyspider.com/product.php?pid={product_id}",
               callback=self.parse, cb_kwargs={'referer': response})

該行正在請求中傳遞一個響應(yīng)引用,它有效地將響應(yīng)生命周期與請求的生命周期聯(lián)系起來,這肯定會導(dǎo)致內(nèi)存泄漏。

讓我們看看如何通過使用 ?trackref? 工具。

當(dāng)爬蟲運(yùn)行幾分鐘后,我們注意到它的內(nèi)存使用量增長了很多,我們可以進(jìn)入它的telnet控制臺并檢查實(shí)時引用:

>>> prefs()
Live References

SomenastySpider                     1   oldest: 15s ago
HtmlResponse                     3890   oldest: 265s ago
Selector                            2   oldest: 0s ago
Request                          3878   oldest: 250s ago

事實(shí)上,存在如此多的實(shí)時響應(yīng)(而且它們太老了),這是絕對可疑的,因?yàn)榕c請求相比,響應(yīng)的生存期應(yīng)該相對較短。響應(yīng)的數(shù)量與請求的數(shù)量相似,因此看起來它們是以某種方式捆綁在一起的。我們現(xiàn)在可以檢查蜘蛛的代碼,以發(fā)現(xiàn)產(chǎn)生泄漏的討厭的行(在請求中傳遞響應(yīng)引用)。

有時,有關(guān)活動對象的額外信息可能會有所幫助。讓我們檢查最早的回答:

>>> 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()? 功能:

>>> 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',
...]

蜘蛛太多了?

如果項(xiàng)目并行執(zhí)行的spider太多,則 ?prefs()? 很難閱讀。因此,該函數(shù)具有 ?ignore? 參數(shù),該參數(shù)可用于忽略特定類(及其所有子類)。例如,這不會顯示對spider的任何實(shí)時引用:

>>> from scrapy.spiders import Spider
>>> prefs(ignore=Spider)

scrapy.utils.trackRef模塊

以下是 ?trackref? 模塊。

classscrapy.utils.trackref.object_ref

如果要使用跟蹤活動實(shí)例,則從該類繼承 trackref 模塊。

scrapy.utils.trackref.print_live_refs(class_nameignore=NoneType)

打印實(shí)時引用的報告,按類名分組。

參數(shù)

ignore (type or tuple) -- 如果給定,則將忽略指定類(或類的元組)中的所有對象。

scrapy.utils.trackref.get_oldest(class_name)

返回具有給定類名的最舊活動對象,或者 None 如果沒有找到。使用 ?print_live_refs()? 首先獲取每個類名的所有跟蹤活動對象的列表。

scrapy.utils.trackref.iter_all(class_name)

返回具有給定類名的所有活動對象的迭代器,或者 None 如果沒有找到。使用 ?print_live_refs()? 首先獲取每個類名的所有跟蹤活動對象的列表。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號