spark 内存管理(源码)1

基本类介绍

spark的内存管理相关的类主要是org.apache.spark.memory包下面(java和scala两部分).
spark的内存管理实际上是对jvm内存的管理的一个逻辑规划,包括分配内存、释放内存等。
image.pngimage.png
org.apache.spark包重点介绍了相关实现类。

package org.apache.spark

/**
 * This package implements Spark's memory management system. This system consists of two main
 * components, a JVM-wide memory manager and a per-task manager:
 * 主要是两个组件,一个是管理JVM的内存,一个是管理单个task的内存
 *
 *  - [[org.apache.spark.memory.MemoryManager]] manages Spark's overall memory usage within a JVM.
 *    This component implements the policies for dividing the available memory across tasks and for
 *    allocating memory between storage (memory used caching and data transfer) and execution
 *    (memory used by computations, such as shuffles, joins, sorts, and aggregations).
 *    MemoryManager 管理整个JVM内存.此组件实现用于在任务之间划分可用内存以及在存储(用于缓存和数据传输的内存)
 *    和执行(计算使用的内存,如随机播放、联接、排序和聚合)之间分配内存的策略。
 *  - [[org.apache.spark.memory.TaskMemoryManager]] manages the memory allocated by individual
 *    tasks. Tasks interact with TaskMemoryManager and never directly interact with the JVM-wide
 *    MemoryManager.
 *    TaskMemoryManager 管理各个任务分配的内存。
 *    任务与 TaskMemoryManager 交互,从不直接与 JVM 范围的 MemoryManager 交互。
 *
 * Internally, each of these components have additional abstractions for memory bookkeeping:
 *
 *  - [[org.apache.spark.memory.MemoryConsumer]]s are clients of the TaskMemoryManager and
 *    correspond to individual operators and data structures within a task. The TaskMemoryManager
 *    receives memory allocation requests from MemoryConsumers and issues callbacks to consumers
 *    in order to trigger spilling when running low on memory.
 *    MemoryConsumers是TaskMemoryManager的客户端,对应于任务中的各个运算符和数据结构。
 *    TaskMemoryManager接收来自MemoryConsumers的内存分配请求,并向消费者发出回调,以便在内存不足时触发溢出。
 *  - [[org.apache.spark.memory.MemoryPool]]s are a bookkeeping abstraction used by the
 *    MemoryManager to track the division of memory between storage and execution.
 *    MemoryPools是MemoryManager用来跟踪存储和执行之间内存划分的薄记抽象。
 *
 * Diagrammatically:
 *
 * {{{
 *                                                              +---------------------------+
 *       +-------------+                                        |       MemoryManager       |
 *       | MemConsumer |----+                                   |                           |
 *       +-------------+    |    +-------------------+          |  +---------------------+  |
 *                          +--->| TaskMemoryManager |----+     |  |OnHeapStorageMemPool |  |
 *       +-------------+    |    +-------------------+    |     |  +---------------------+  |
 *       | MemConsumer |----+                             |     |                           |
 *       +-------------+         +-------------------+    |     |  +---------------------+  |
 *                               | TaskMemoryManager |----+     |  |OffHeapStorageMemPool|  |
 *                               +-------------------+    |     |  +---------------------+  |
 *                                                        +---->|                           |
 *                                        *               |     |  +---------------------+  |
 *                                        *               |     |  |OnHeapExecMemPool    |  |
 *       +-------------+                  *               |     |  +---------------------+  |
 *       | MemConsumer |----+                             |     |                           |
 *       +-------------+    |    +-------------------+    |     |  +---------------------+  |
 *                          +--->| TaskMemoryManager |----+     |  |OffHeapExecMemPool   |  |
 *                               +-------------------+          |  +---------------------+  |
 *                                                              |                           |
 *                                                              +---------------------------+
 * }}}
 *
 *
 * There is one implementation of [[org.apache.spark.memory.MemoryManager]]:
 *
 *  - [[org.apache.spark.memory.UnifiedMemoryManager]] enforces soft
 *    boundaries between storage and execution memory, allowing requests for memory in one region
 *    to be fulfilled by borrowing memory from the other.
 *    UnifiedMemoryManager在存储和执行内存之间强制执行软边界,允许通过从另一个区域借用内存来满足对一个区域内存的请求。
 */
package object memory

image.png
MemConsumer是spark中不同组件和场景使用内存的客户端(TaskMemoryManager的客户端),使用它来操作内存。
TaskMemoryManager是管理task的内存,它是MemoryManager的客户端。
MemoryManager管理jvm内存,分成四个内存池:

  • OnHeapStorageMemPool 堆内存储内存池
  • OffHeapStorageMemPool 堆外存储内存池
  • OnHeapExecMemPool 堆内执行内存池
  • OffHeapExecMemPool 堆外执行内存池

image.png

MemoryPool

MemoryPool是一个动态调节大小的内存池。

StorageMemoryPool

存储内存池,主要方法有四个。

  • memoryUsed 获取已经使用的内存大小
  • acquireMemory 申请内存
  • releaseMemory 释放内存
  • freeSpaceToShrinkPool 收缩内存池(为了给执行内存池腾出更多的内存)

image.png

memoryUsed

_memoryUsed变量是用来记录内存使用大小。
image.png

acquireMemory

image.png

releaseMemory

image.png

freeSpaceToShrinkPool

freeSpaceToShrinkPool是在收缩内存池之前调用的,返回要收缩的值。它并不执行实际收缩的动作。
image.png

ExecutionMemoryPool

image.png
执行内存池,主要属性和方法有四个:

  • memoryForTask map结构,记录了task和它对应内存大小的关系
  • memoryUsed 使用的总内存大小
  • acquireMemory 申请内存
  • releaseAllMemoryForTask 释放内存

memoryUsed

使用的总内存大小memoryUsed是每个task使用内存之和。
image.png

acquireMemory

  1. 添加task到memoryForTask中,此时task数量发生改变,通知线程(此处指未能申请到内存的等待线程)可以重新申请内存
  2. 判断是否需要扩容,需要的话就扩容
  3. 计算可以申请的内存大小 toGrant
  4. toGrant大于此次申请的内存 numBytes,同时 curMem + toGrant < minMemoryPerTask,标识此时申请的内存不够,阻塞当前线程。等待内存释放或者task数量变化后唤醒。重复2~4,直到申请到足够的内存。

image.png
扩容 maybeGrowPool
image.png

releaseMemory

释放内存完成后,唤醒线程,通知可以申请内存。
image.png

MemoryManager

用四个MemoryPool来记录和管理内存。
堆外的两个pool大小默认都是0.不参与管理
堆内的两个pool是有onHeapStorageMemory和onHeapExecutionMemory决定,这两个参数是创建MemoryManager时传入的。
image.png
从功能上看,主要是管理三类内存(ExecutionMemory、StorageMemory、UnrollMemory)的申请和释放。
UnrollMemory 是指数据读取过程,不知道具体需要多大内存,所以可以随着数据增多,UnrollMemory会不断扩大,最后将数据全部读取到内存。最后UnrollMemory会转变为StorageMemory。
image.png
内存申请都是在实现类(UnifiedMemoryManager)中实现的。
image.png
内存释放比较简单,对应的内存池释放内存即可。
image.png

UnifiedMemoryManager

内存的申请也是操作的内存池来申请内存。
UnrollMemory内存申请就是StorageMemory内存申请。
StorageMemory申请过程中StoragePool空间不够,会向ExecutionPool借用其剩余内存。
ExecutionMemory申请过程中ExecutionPool空间不够,会向StoragePool借用,StoragePool会将缓存的block驱除,腾出空间来给ExecutionPool。
image.png

内存模型


内存模型划分在UnifiedMemoryManager的伴生对象中。
image.png

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值