不要になったRDDがある場合、それをメモリから削除するにはどうすればよいですか?これを行うには、次の情報で十分でしょうか。
del thisRDD
ありがとう!
いいえ、_del thisRDD
_では不十分です。RDDへのポインタを削除するだけです。キャッシュされたデータを削除するには、thisRDD.unpersist()
を呼び出す必要があります。
参考までに、Sparkは遅延計算のモデルを使用しています。つまり、このコードを実行すると、
_>>> thisRDD = sc.parallelize(xrange(10),2).cache()
_
実際にキャッシュされるデータはなく、RDD実行プランでは 'to be cached'としてのみマークされます。次の方法で確認できます。
_>>> print thisRDD.toDebugString()
(2) PythonRDD[6] at RDD at PythonRDD.scala:43 [Memory Serialized 1x Replicated]
| ParallelCollectionRDD[5] at parallelize at PythonRDD.scala:364 [Memory Serialized 1x Replicated]
_
ただし、このRDDの上でアクションを少なくとも1回呼び出すと、キャッシュされます。
_>>> thisRDD.count()
10
>>> print thisRDD.toDebugString()
(2) PythonRDD[6] at RDD at PythonRDD.scala:43 [Memory Serialized 1x Replicated]
| CachedPartitions: 2; MemorySize: 174.0 B; TachyonSize: 0.0 B; DiskSize: 0.0 B
| ParallelCollectionRDD[5] at parallelize at PythonRDD.scala:364 [Memory Serialized 1x Replicated]
_
Spark UIで、アドレス_http://<driver_node>:4040/storage
_を使用して永続化データと永続性のレベルを簡単に確認できます。_del thisRDD
_が永続性を変更しないことがわかります。このRDDの、しかしthisRDD.unpersist()
は永続化しませんが、コードでthisRDDを使用することはできます(メモリ内に永続化されなくなり、クエリが実行されるたびに再計算されます)
短い答え:次のコードでうまくいくはずです:
_import gc
del thisRDD
gc.collect()
_
説明:
PySparkを使用している場合でも、RDDのデータはJava側で管理されるため、最初に同じ質問をしてみましょう。ただし、PythonではなくJavaを使用します。
Javaを使用していて、RDDへのすべての参照を解放するだけの場合、自動的に永続化を解除するのに十分ですか?
Javaの場合、答えはYESです。 この答え によると、RDDはガベージコレクションされると自動的に永続化されません。 (どうやらその機能は this PR のSparkに追加されました。)
OK、Pythonでは何が起こりますか? PythonでRDDへのすべての参照を削除すると、Java側でそれらが削除されますか?
PySparkは Py4J を使用して、オブジェクトをPythonからJavaに、またはその逆に送信します。 Py4Jメモリモデルドキュメント によると:
オブジェクトがPython VM(参照カウント== 0)でガベージコレクションされると、Java VMで参照が削除されます
ただし、注意してください。RDDへのPython参照を削除しても、RDDはすぐに削除されません。 Pythonガベージコレクターが参照をクリーンアップするまで待つ必要があります。詳細については、Py4Jの説明を参照してください。
gc.collect()
の呼び出しも通常は機能します。
では、元の質問に戻りましょう。
これを行うには、次で十分でしょう:
_del thisRDD
_
ほぼ。最後の参照(つまり、_del thisRDD
_)を削除し、RDDをすぐに永続化する必要がある場合**、gc.collect()
を呼び出します。
**まあ、技術的には、これはJava側のreferenceをすぐに削除しますが、Javaのガベージコレクターが実際にRDDを実行するまで、少し遅延がありますファイナライザにより、データが非永続化されます。
短い答え:場合によります。
pyspark v.1.3.0ソースコード によると、PipelinedRDD
にはdel thisRDD
で十分です。これは、Pythonによって生成されるRDDです。マッパー/リデューサー:
class PipelinedRDD(RDD):
# ...
def __del__(self):
if self._broadcast:
self._broadcast.unpersist()
self._broadcast = None
一方、RDD
クラスには__del__
メソッドがないので(おそらく必要です)、自分でunpersist
メソッドを呼び出す必要があります。
編集:__del__
メソッドが this コミットで削除されました。
参考までに、del
の後にgc.collect()
をお勧めします(rddが大量のメモリを使用する場合)。