I am struggling to make my Spark program avoid exceeding YARN memory limits (on executors).
The "known" error which I get is:
Container killed by YARN for exceeding memory limits. 3.8 GB of 3.6 GB physical memory used.
Instead of just raising the executor memory, executor memory overhead or tune my resources or partitions, I'de like to know why my off heap memory is expanding at all.
I'm using pyspark v2.4.4, as far as I understand YARN memory overhead (for executors) is any off heap memory allocated by my Spark program (outside JVM).
The only additional "non-related" off heap memory I'm aware of is the Python memory, which is not not part of the memory overhead by Spark documentation:
The maximum memory size of container to running executor is determined by the sum of spark.executor.memoryOverhead, spark.executor.memory, spark.memory.offHeap.size and spark.executor.pyspark.memory.
I'm using heavy caching in my program; disabling the persist call somehow remedies the memory overhead issue (less executors die and the program can finish eventually), but since this data should be managed only inside the JVM/disk against the execution memory with UnifiedMemoryManager, it shouldn't use any off heap memory.
Since off heap mode is disabled by default (spark.memory.offHeap.use), which scenarios may cause expanding memory overhead, and why disabling caching in my program helps to reduce the overhead size?
Edit
Using larger executors (twice memory and cores) remedies this as well.
It's makes sense that larger memory on JVM means larger overhead (10% when larger than 386m), but still we are using 2 cores (i.e 2 tasks) on this JVM and I don't understand on which situations memory overhead expands.