2011-01-27 21 views
6

私はdocumentation for Memory Management in Python C extensionsを読んでいると、私の知る限り、本当にmallocではなくPyMem_Mallocを使用するには多くの理由があるようには思えません。私はPythonのソースコードに公開されていない配列を割り当てたいとし、ガベージコレクションされるオブジェクトに格納されます。 mallocを使用する理由はありますか?PyMem_Mallocよりmallocを使用する理由はありますか?

答えて

5

編集:混合PyMem_MallocPyObject_Mallocの修正。彼らは2つの異なる呼び出しです。なし

PYMALLOC_DEBUGマクロ、PyMem_Malloc一つの特別なケースを有する、のlibcのmalloc()の別名である活性化:のmalloc(zero_bytes)がNULL値を返すか、上げるかもしれないが、非NULLポインタを戻しますゼロバイトを割り当てるPyMem_Mallocを呼び出しますシステムエラー(source code reference):

/* malloc。 nbytes == 0は、 がNULLポインタでないものを返すことを試みることに注意してください。 *は、他のすべてのライブポインタから区別されます。これは不可能かもしれません。 */

はまた、助言ノートはpymem.h header fileにあります:

プラットフォームのmalloc/reallocを/ のcalloc /自由へ 呼び出しにPyMem_への呼び出しを混在させることはありません。たとえば、Windowsの場合 異なるDLLは 異なるヒープを使用して終了し、 PyMem_Mallocを使用すると、Python DLLによって使用されるヒープからメモリ が取得されます。 あなた自身が直接 エクステンションにfree()した場合、災害になる可能性があります。 PyMem_Freeを代わりに使用する Pythonが のメモリを適切なヒープに返すことを保証します。別の 例として、PYMALLOC_DEBUGモードでは、 Pythonは 動的メモリブロックへ 追加のデバッグ情報を追加 デバッグ用の特別なラッパーのすべてのPyMem_ とPyObject_メモリ機能に対するすべての呼び出しをラップします。システム ルーチンは何をするべきか分かりません。 そのようなもので、Python ラッパーは何をするべきか分かりません ローブブロックを で直接取得してシステムルーチンを実行します。

:Pythonプログラムを実行しながら

PyMem_Malloc PyObject_Malloc内部いくつかのPythonの特定のチューニングがあり、機能は100*234str(100)又は10 + 4jように、Cの拡張のためではなく、すべての動的割り当てのためだけでなく、使用します

>>> id(10 + 4j) 
139721697591440 
>>> id(10 + 4j) 
139721697591504 
>>> id(10 + 4j) 
139721697591440 

前のcomplex()インスタンスは専用プールに割り当てられた小さなオブジェクトです。

小さな物体(< 256バイト) PyMem_Malloc PyObject_Mallocと割り当て、それが各ブロックサイズのために1つのプールを、既存のブロックを整列プールから8つのバイトを行っていますので、非常に効率的です。より大きな割り当てのためのPagesとArenasブロックもあります。

source code上のこのコメントはPyObject_Malloc呼び出しが最適化されている方法について説明します。

/* 
* The basic blocks are ordered by decreasing execution frequency, 
* which minimizes the number of jumps in the most common cases, 
* improves branching prediction and instruction scheduling (small 
* block allocations typically result in a couple of instructions). 
* Unless the optimizer reorders everything, being too smart... 
*/ 

プールを、ページとアリーナは、長時間実行されているPythonプログラムのexternal memory fragmentationを減少させることを意図した最適化されています。

Pythonのメモリ内部に関する詳細な文書については、the source codeを参照してください。

+0

ネイティブアロケータは既に非常に最適化されています。拡張モジュールには何の影響もありません。 –

+0

@Glennあなたはそれをサポートするために堅い番号を使いますか?ドキュメントは非常に広範で、詳細を「オーバーヘッドにするオーバーヘッド」にすぎません。 – vz0

+0

私は経験と常識を持っています。システムアロケータはシステム全体の速度に影響します。そのため、システムアロケータはシステムの速度を最適化するために多くの労力を要します。 Pythonがそれを改善していると主張しているのであれば、低レベルのPythonコアの特殊なケースだけでなく、拡張モジュールの使用のために、それを改善すると主張しているのです。 –

1

私がMATLABの.mex関数を書いた経験から、mallocを使うかどうかの最大の決定要因は移植性だと思います。内部のcデータ型(必要なPythonオブジェクトの相互作用がないため、mallocを使用しても問題ない)を使用して便利な関数をロードするヘッダーファイルがあり、そのヘッダーファイルを別のコードベースPythonとはまったく関係がありません(C言語で書かれたプロジェクトかもしれません)、mallocを使うことははるかにポータブルなソリューションになるはずです。

しかし、純粋にPythonの拡張機能であるあなたのコードのために、私の最初の反応は、ネイティブC関数が速く実行することを期待するだろう。私はこれをバックアップする証拠がありません:)

+2

ネイティブのC関数が優れたパフォーマンスを発揮することは間違いありません。問題は、両方ともネイティブのC関数であることです。 :-) –

+1

さて、私は彼らが素敵なテクニカルだと思っています:)私は、Cのネイティブメモリ割り当てシステムが、Pythonのメモリ割り当てシステム用に実装されたネイティブCより高速であると思っていると思っています。P – William

+2

私はmallocとPyMem_Mallocの両方。私のベンチマークでは、この2つのパフォーマンスの差は無視できるものでした。 PyMem_Mallocの方が速いかもしれませんが、統計的に有意な差はないと思います。もちろん、YMMV。 – casevh

6

拡張機能がmallocまたは他のシステムアロケータでメモリを割り当てることは完全に問題ありません。これは普通のことですが、多くのタイプのモジュールでは避けられません。Pythonについて何も知らない他のライブラリをラップするほとんどのモジュールは、そのライブラリ内でネイティブの割り当てを行います。 (いくつかのライブラリは、あなたがこれを防ぐのに十分な割り当てを制御することができ、ほとんどはしないでください。)

PyMem_Mallocを使用することの重大な欠点があります:あなたはそれを使用するときにGILを保持する必要があります。ネイティブライブラリは、CPU集約的な計算やI/Oのようなブロックする可能性のある呼び出しを行うときに、GILを解放したいことがよくあります。割り当ての前にGILをロックする必要があると、非常に不便な点とパフォーマンスの問題の間にある可能性があります。

メモリ割り当て用のPythonのラッパーを使用すると、Pythonのメモリデバッグコードを使用できます。 Valgrindのようなツールでは、私は実際の価値を疑っています。

APIで必要な場合は、これらの関数を使用する必要があります。たとえば、APIにこれらの関数で割り当てられなければならないポインタが渡されているため、それらの関数で解放することができます。そのような明示的な理由を除いて、私は通常の割り当てをしています。

関連する問題