我有以下最低限度的工作示例:
from pyspark import SparkContext
from pyspark.sql import SQLContext
import numpy as np
sc = SparkContext()
sqlContext = SQLContext(sc)
# Create dummy pySpark DataFrame with 1e5 rows and 16 partitions
df = sqlContext.range(0, int(1e5), numPartitions=16)
def toy_example(rdd):
# Read in pySpark DataFrame partition
data = list(rdd)
# Generate random data using Numpy
rand_data = np.random.random(int(1e7))
# Apply the `int` function to each element of `rand_data`
for i in range(len(rand_data)):
e = rand_data[i]
int(e)
# Return a single `0` value
return [[0]]
# Execute the above function on each partition (16 partitions)
result = df.rdd.mapPartitions(toy_example)
result = result.collect()
运行上述命令后,执行程序的Python进程的内存在每次迭代后稳步增加,这表明上一迭代的内存并未释放-即内存泄漏。如果内存超出执行程序的内存限制,则可能导致作业失败-见下文:
Bizarrely以下任何一项都可以防止内存泄漏:
data = list(rdd)
rand_data = list(rand_data.tolist())
之后插入行rand_data = np.random.random(int(1e7))
int(e)
以上代码是一个大型项目的最小工作示例,该项目无法使用上述修复程序。
一些需要注意的事情:
rdd
数据时,需要使用该行来重现泄漏。在现实世界的项目中,使用rdd
数据。rand_data
int
的每个元素执行rand_data
操作才能重现泄漏您可以通过在rand_data
函数的前几行或后几行插入代码来强制PySpark执行程序释放toy_example
的内存吗?
通过在函数末尾插入来强制进行垃圾回收:
del data, rand_data
import gc
gc.collect()
通过在函数的结尾或开头插入来强制释放内存(受Pandas issue的启发):
from ctypes import cdll, CDLL
cdll.LoadLibrary("libc.so.6")
libc = CDLL("libc.so.6")
libc.malloc_trim(0)
以下PySpark作业在具有一个m4.xlarge工作程序节点的AWS EMR集群上运行。 Numpy必须通过bootstrapping通过pip安装在工作程序节点上。
执行器的内存使用以下功能(打印在执行器的日志中)进行测量:
import resource
resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
火花提交配置:
版本:
答案 0 :(得分:0)
我们最近遇到了一个非常类似的问题,我们也无法通过更改代码来强制释放内存。但是,对我们有用的是使用以下Spark选项:
spark.python.worker.reuse = False