spark内存管理

一.spark内存管理只堆内存/堆外内存前世今生

1.堆内存和对外内存

作为jvm进程,executor的内存管理建立在jvm之上,spark对jvm的堆内空间进行了更为详细的分配,以充分利用内存,

1.1堆内存的大小

堆内存的大小,由spark应用程序启动的executor-memory或spark-executor-memory参数配置,Executor内运行的并发任务共享JVM堆内内存,这些任务在缓存RDD和广播(Broadcast)数据时占用的内存被规划为存储(Storage)内存,而这些任务在执行Shuffle时占用的内存被规划为执行(Execution)内存

1.1.1.内存的申请和释放

spark在代码中new一个对象实例,jvm从堆内存分配空间,创建对象并返回对象引用,spark保存该对象的引用,记录该对象占用的内存.

释放内存:spark记录该对象释放的内存,删除该对象的引用,等待jvm垃圾回收机制释放该对象占用的堆内存

2.堆内存的优缺点分析

堆内存采用jvm进行管理,而jvm的对象可以序列化,的方式存储,而序列化的方式本质就是把对象转换成字节流,本质上可以理解为将非连续空间的链式存储,转化为连续空间或块存储,则在访问时需要进行反序列化过程,序列化的方式节省了存储空间,但增加了读取和存储时的计算开销.

spark中序列化的对象,由于是字节流的形式,其占用的内存大小可以直接计算,

spark中非序列化的对象,其占用内存是通过周期性的采样近似估算得到的,及并不是每次新增的数据都会计算到,这种计算方法虽然降低时间开销,但是可能会造成的误差比较大,导致某一时刻的实际内存有可能远远超出预期,

此外,在被Spark标记为释放的对象实例,很有可能在实际上并没有被JVM回收,导致实际可用的内存小于Spark记录的可用内存。所以Spark并不能准确记录实际可用的堆内内存,从而也就无法完全避免内存溢

executor端的堆内内存区域大致可以分为四大块

executor:主要存放shuffle,join,sort,aggregation,等计算的临时数据,

storage内存:主要存储spark的cache数据列入缓存:unroll,RDD的缓存,

用户内存(User Memory) 主要用于存储RDD转换操作所需要的的数据,,例如RDD

预留内存(Reserved Memory) 系统预留内存,会用来存储spark内部对象

2.2堆外内存

特点:堆外内存,spark直接绕开jvm直接向操作系统申请内存,所以可以避免频繁的 GC,这种内存申请的缺点是必须自己编写内存申请和释放的逻辑。

堆内外内存的优缺点

Spark可以直接操作系统堆外内存,减少了不必要的内存开销,以及频繁的GC扫描和回收,提升了处理性能。堆外内存可以被精确地申请和释放,而且序列化的数据占用的空间可以被精确计算,所以相比堆内内存来说降低了管理的难度,也降低了误差。

缺点:可用的执行内存和存储内存占用的空间大小直接由参数spark.memory.storageFraction决定,由于堆外内存占用的空间可以被精确计算,所以无需再设定保险区域。

2.3spark新旧版本关于静态存储和动态存储的对比

在spark15版本以前storage和execution是静态存储的也就是如果execution内存就算存满了storage内存有很大的存储空间也无法被利用,反正依然,这样就给开发者很大的调优工作,开发者在必须非常清楚的知道execution 和storag两块区域的内存分析,

而spark3.0之后execution和storage内存可相互共享,也就是说如果execution内存不足可以从storage申请资源,反之亦然,如果双方存储都不足时则存储到硬盘里面,存储到磁盘的策略是,按照LUR规则,若己方空间不足而对方空间空余时可借对方空间,execution的空间被占用时,可将被占用的部分转移到磁盘上,然后归还该部分空间,而storage被占用空间后,是无法让对方归还的,

3 Task内存申请流程

  • 当 Task 需要在 Execution 内存区域申请 numBytes 内存,其先判断 HashMap 里面是否维护着这个 Task 的内存使用情况,如果没有,则将这个 Task 内存使用置为0,并且以 TaskId 为 key,内存使用为 value 加入到 HashMap 里面。
  • 之后为这个 Task 申请 numBytes 内存,如果 Execution 内存区域正好有大于 numBytes 的空闲内存,则在 HashMap 里面将当前 Task 使用的内存加上 numBytes,然后返回;如果当前 Execution 内存区域无法申请到每个 Task 最小可申请的内存,则当前 Task 被阻塞,直到有其他任务释放了足够的执行内存,该任务才可以被唤醒。
  • 每个 Task 可以使用 Execution 内存大小范围为 1/2N ~ 1/N,其中 N 为当前 Executor 内正在运行的 Task 个数。
  • 一个 Task 能够运行必须申请到最小内存为 (1/2N * Execution 内存);当 N = 1 的时候,Task 可以使用全部的 Execution 内存。比如如果 Execution 内存大小为 10GB,当前 Executor 内正在运行的 Task 个数为5,则该 Task 可以申请的内存范围为 10 / (2 * 5) ~ 10 / 5,也就是 1GB ~ 2GB的范围。

 

  • 好处就是内存由JVM进行管理,比较省事,但是如过在运行的过程中产生了大量的垃圾,还没来得及下一次回收,而我们程序需要大量的内存,这样就有可能会造成内存溢出,
  • executor内运行的并发任务,共享jvm内存,这些任务在缓存RDD和广播数据时占用的内存,被规划为存储内存,而这些任务在执行shuffle时别规划为执行内存,
  • 静态内存管理
    • 分为存储内存,执行内存,和其他内存,这些内存都是静态的,需要户在应用程序启动之前,进行配置,
    • 对于存储内存占总内存的60%,在这60%中有90%是用来存储的,剩余10%用来预防内存溢出的 ,
    • 还有另外40% ,这40%中,有20%是为执行时分配的内存,比如我们在执行的时候,需要逆写磁盘,把数据放到market里面,达到一定大小就写入磁盘里面,但是在这20%的执行内存里面,有留了20%,也是为了防止OOM(内存溢出)

最后20%的内存,就留给other数据

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值