![](/img/trans.png)
[英]Python Starting Java application with subprocess:Invalid maximum heap size
[英]Why does an object allocation local to a Python subprocess increase heap size for main?
根據Valgrind的memcheck工具,如果我在一個函數中分配一個較大的局部變量並使用multiprocessing.Pool().apply_async()
啟動該函數,則子進程和主進程的堆大小都會增加。 為什么main的堆大小會增加?
我正在與一個多進程工作池一起工作,每個工作人員都將處理輸入文件中的大量數據。 我想看看我的內存占用量如何根據輸入文件的大小縮放。 為此,我使用memcheck和此SO Answer中描述的技術在Valgrind下運行了腳本。 (此后,我了解到Valgrind的Massif工具更適合於此,因此我將繼續使用它。)
我希望幫助了解memcheck輸出中有些奇怪的東西。
我在Red Hat Linux上使用CPython 2.7.6,並像這樣運行memcheck:
valgrind --tool = memcheck --suppressions =。/ valgrind-python.supp python test.py
import multiprocessing
def mem_user():
tmp = 'a'*1
return
pool = multiprocessing.Pool(processes=1)
pool.apply_async(mem_user)
pool.close()
pool.join()
堆摘要(每個進程一個):
堆總使用量:45,193個分配,32,392個釋放,7,221,910字節分配
堆總使用量:44,832分配,22,006釋放,7,181,635字節分配
如果將tmp = 'a'*1
行更改為tmp = 'a'*10000000
得到以下摘要:
總堆使用量:44,835個分配,22,009個釋放,27,181,763字節已分配
堆總使用量:45,195個分配,32,394個空閑,17,221,998字節分配
為什么兩個進程的堆大小都會增加? 我知道對象的空間是在堆上分配的 ,因此較大的堆對於其中一個進程當然是有意義的。 但是我希望子進程具有自己的堆,堆棧和解釋器實例,所以我不明白為什么在子進程中分配的局部變量也會增加main的堆大小。 如果它們共享相同的堆,那么CPython是否實現自己的fork()版本,該版本不會為子進程分配唯一的堆空間?
問題與fork
的實現方式無關。 您可以自己看到, multiprocessing
調用os.fork
,這是一個非常薄的fork
封裝。
那么,這是怎么回事?
編譯器看到源代碼中的'a' * 10000000
並將其優化為10000000個字符的文字。 這意味着模塊對象現在要長10000000字節,並且由於在兩個進程中都將其導入,因此它們都變得更大。
要看到這個:
$ python2.7
>>> def f():
... temp = 'a' * 10
...
>>> f.__code__.co_consts
(None, 'a', 10, 'aaaaaaaaaa')
>>> import dis
>>> dis.dis(f)
2 0 LOAD_CONST 3 ('aaaaaaaaaa')
3 STORE_FAST 0 (temp)
6 LOAD_CONST 0 (None)
9 RETURN_VALUE
請注意,編譯器足夠聰明,可以將'aaaaaaaaaa'
添加到常量中,但是不足以刪除'a'
和10
。 那是因為它使用了非常狹窄的窺孔優化器。 除了它不知道您是否還在同一函數中的其他位置使用'a'
這一事實外,它還不想從co_consts
列表的中間刪除一個值,然后返回並更新所有其他字節碼為使用上移的索引。
我實際上不知道為什么子級最終以20000000個字節而不是10000000個字節增長。大概它以其自己的模塊或至少代碼對象的副本結尾,而不是使用父級共享的副本。 但是,如果我嘗試print id(f.__code__)
或其他任何內容,那么我在父級和子級中會得到相同的值,所以……
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.