本地模式PySpark仅处理2条记录内存持续上涨问题排查
PySpark本地模式小数据量内存未释放问题原因
- DataFrame血缘链条留存占用内存
PySpark的转换操作是懒执行的,你在12个process_orderh_step子函数中生成的所有中间DataFrame,哪怕反复赋值给同一个df7_2变量,其血缘信息都会被挂载到最终的df7_2的血缘链上用于容错重算,不会因为变量被覆盖就被垃圾回收。每个转换步骤的元数据、执行计划对象都会在Driver端常驻,多步骤累计的元数据会占用远超实际数据量的内存。 - 本地模式Driver内存预分配机制
你配置了spark.driver.memory=12g,JVM会优先预占用大块内存区域,哪怕实际运行只用到很小一部分,也不会主动将内存归还给操作系统,你观测到的进程高内存占用很多时候是JVM预申请的堆内存,而非实际对象的占用大小。同时PySpark的Python进程与JVM进程之间的通信缓冲区默认也会占用数百MB的常驻内存。 - 隐式缓存与广播变量未释放
如果process_orderh_step子函数中使用了cache()、persist()操作,哪怕变量被覆盖,被缓存的DataFrame分区数据会一直存储在Driver内存中,只有主动调用unpersist()才会释放。如果子函数中用到了广播变量,未主动销毁的情况下也会长期占用内存。 - Python端对象引用未解除
你仅将中间结果统一赋值给df7_2,但如果子函数内部还有其他变量引用了中间DataFrame对象,或是Spark Python API的上下文对象持有了这些中间对象的引用,Python GC就无法回收对应对象,JVM端关联的DataFrame实例也会一直留存。 - 执行计划与任务序列化开销
调用show(truncate=False)这个Action算子时,Spark需要序列化完整执行计划、序列化所有阶段的任务对象,哪怕只处理2行数据,这部分开销是固定的,12个转换步骤叠加后很容易达到数百MB到1GB的占用规模。
内容的提问来源于stack exchange,提问作者Arthur
相关产品推荐
相关产品推荐

