Spark源码[6]-Task内存
2020-05-24 本文已影响0人
蠟筆小噺没有烦恼
位于spark-core模块的org.apache.spark.memory.TaskMemoryManager
1 简介
TaskMemoryManager用于管理单个任务尝试的内存分配与释放,其依赖于MemoryManger的内存管理能力。
比较重要的成员包括:
PAGE_NUMBER_BITS = 13 #存储页号,寻址page的位数,使用长整型64位的最高13位
OFFSET_BITS = 64 - PAGE_NUMBER_BITS #保存编码后的偏移量的位数,用长整型的底51位
MAXIMUM_PAGE_SIZE_BYTES = ((1L << 31) - 1) * 8L #最大page大小
MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL #长整型的底51位掩码
PAGE_TABLE_SIZE = 1 << PAGE_NUMBER_BITS #Page表的page数量,8192页
pageTable = new MemoryBlock[PAGE_TABLE_SIZE] #page表,实际为Page的数组,page也就是MemoryBlock
2 提供的方法
TaskMemoryManager有两个重要的内存申请方法:acquireExecutionMemory是针对堆内内存,按照字节进行计数。而allocatePage是和Tungsten一起引入,使用页存来管理内存,并且支持堆外内存的申请。
2.1 申请执行内存-acquireExecutionMemory
位于spark-core模块的org.apache.spark.memory.TaskMemoryManager
1 简介
TaskMemoryManager用于管理单个任务尝试的内存分配与释放,其依赖于MemoryManger的内存管理能力。
比较重要的成员包括:
PAGE_NUMBER_BITS = 13 #存储页号,寻址page的位数,使用长整型64位的最高13位
OFFSET_BITS = 64 - PAGE_NUMBER_BITS #保存编码后的偏移量的位数,用长整型的底51位
MAXIMUM_PAGE_SIZE_BYTES = ((1L << 31) - 1) * 8L #最大page大小
MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL #长整型的底51位掩码
PAGE_TABLE_SIZE = 1 << PAGE_NUMBER_BITS #Page表的page数量,8192页
pageTable = new MemoryBlock[PAGE_TABLE_SIZE] #page表,实际为Page的数组,page也就是MemoryBlock
2 提供的方法
TaskMemoryManager有两个重要的内存申请方法:acquireExecutionMemory是针对堆内内存,按照字节进行计数。而allocatePage是和Tungsten一起引入,使用页存来管理内存,并且支持堆外内存的申请。
2.1 申请执行内存-acquireExecutionMemory
申请内存方法用于位内存消费者指定大小(字节),如果内存不足,调用MemoryConsumer的spill先进行内存释放。
- 首先调用MemoryManager.acquireExecutionMemory申请目标大小的执行内存;
- 如果申请到的内存小于期望的内存大小(got < required);则遍历所有MemoryConsumer(除了当前申请者),尝试进行spill数据溢写。遍历中如果有consumer释放了内存,则调用MemoryManager.acquireExecutionMemory将内存加到got中,如果释放的内存和已申请到的内存大于了需要申请的内存,则停止下面的consumer遍历。
- 如果遍历了所有的MemoryConsumer,got依然小于required,则,对当前的MemoryConsumer进行spill,并调用MemoryManager.acquireExecutionMemory做最后尝试。
- 将当前consumer加入到consumers中,并返回实际申请到的内存。
2.2 以页的方式申请内存-allocatePage
用于位内存消费者指定大小(字节),如果内存不足,调用MemoryConsumer的spill先进行内存释放。
- 首先调用MemoryManager.acquireExecutionMemory申请目标大小的执行内存;
- 如果申请到的内存小于期望的内存大小(got < required);则遍历所有MemoryConsumer(除了当前申请者),尝试进行spill数据溢写。遍历中如果有consumer释放了内存,则调用MemoryManager.acquireExecutionMemory将内存加到got中,如果释放的内存和已申请到的内存大于了需要申请的内存,则停止下面的consumer遍历。
- 如果遍历了所有的MemoryConsumer,got依然小于required,则,对当前的MemoryConsumer进行spill,并调用MemoryManager.acquireExecutionMemory做最后尝试。
- 将当前consumer加入到consumers中,并返回实际申请到的内存。