Spark Task 内存管理(on-heap&off-heap)

本文为 Spark 2.0 源码分析,其他版本可能会有所不同

在之前的文章中(Spark 新旧内存管理方案(上)Spark 新旧内存管理方案(下)),我从粗粒度上对 Spark 内存管理进行了剖析,但我们依然会有类似这样的疑问,在 task 中,shuffle 时使用的内存具体是怎么分配的?是在堆上分配的还是堆外分配的?堆上如何分配、堆外又如何分配?

这些问题可以通过剖析 TaskMemoryManager 来解决。TaskMemoryManager 用来管理一个 task 的内存,主要涉及申请内存、释放内存及如何表示统一的表示从堆或堆外申请的一块固定大小的连续的内存

统一的内存块表示 - MemoryBlock

对于堆内存,分配、释放及对象引用关系都由 JVM 进行管理。new 只是返回一个对象引用,而不是该对象在进程地址空间的地址。堆内存的使用严重依赖 JVM 的 GC 器,对于大内存的使用频繁的 GC 经常会对性能造成很大影响。

Java 提供的 ByteBuffer.allocateDirect 方法可以分配堆外内存,其分配大小受 MaxDirectMemorySize 配置限制。另一种分配堆外内存的方法就是 Unsafe 的 allocateMemory 方法,相比前者,它完全脱离了 JVM 限制,与 C 中的 malloc 功能一致。这两个方法还有另一个区别:后者返回的是进程空间的实际内存地址,而前者被 ByteBuffer 进行包装。

堆内内存使用简单,但在使用大内存时其 GC 机制容易影响性能;堆外内存相交于堆内存使用复杂,但精确的内存控制使其更高效。在 Spark 中,很多地方会有大数组大内存的需求,高效的内存使用时必须的,因此 Spark 也提供了堆外内存的支持,以优化 Application 运行性能。

Spark 封装了 MemoryLocation 来表示一个逻辑内存地址,其定义如下:

public class MemoryLocation {
  Object obj;
  long offset;

  //< 适用于堆内内存
  public MemoryLocation(@Nullable Object obj, long offset) {
    this.obj = obj;
    this.offset = offset;
  }

  //< 适用于堆外内存
  public MemoryLocation() {
    this(null, 0);
  }

  ...
}

以及 MemoryBlock 来表示一块连续的内存,这块内存可以从堆或对外分配,包含以下成员:

  • length:内存块大小
  • pageNumber:page id(这块内存又被叫做 page)
  • obj:见下文分析
  • offset:见下文分析
public class MemoryBlock extends MemoryLocation {

  private final long length;
  public int pageNumber = -1;

  public MemoryBlock(@Nullable Object obj, long offset, long length) {
    super(obj, offset);
    this.length = length;
  }

  ...
}

接下来我们来看看如何从堆内和堆外申请内存并生成对应的 MemoryBlock 对象。

申请堆外内存

Spark 封装了 UnsafeMemoryAllocator 类来分配和释放堆外内存,分配的方法如下:

  public MemoryBlock allocate(long size) throws OutOfMemoryError {
    long address = Platform.allocateMemory(size);
    return new MemoryBlock(null, address, size);
  }

其中 Platform.allocateMemory(size) 会调用 Unsafe.allocateMemory 来从堆外分配一块 size 大小的内存并返回其绝对地址。随后,构造并返回 MemoryBlock 对象,需要注意的是,该对象的 obj 成员为 null,offset 成员为该绝对地址

申请堆内存

Spark 封装了 HeapMemoryAllocator 类分配和释放堆内存,分配的方法如下:

  public MemoryBlock allocate(long size) throws OutOfMemoryError {
    ...
    long[] array = new long[(int) ((size + 7) / 8)];
    return new MemoryBlock(array, Platform.LONG_ARRAY_OFFSET, size);
  }

总共分为两步:

  1. 以8字节对齐的方式申请长度为 ((size + 7) / 8) 的 long 数组,得到 array
  2. 构造 MemoryBlock 对象,其 obj 成员为 array,offset 成员为 Platform.LONG_ARRAY_OFFSET

Page table

在 TaskMemoryManager 有一个如下成员:

private final MemoryBlock[] pageTable = new MemoryBlock[8192];

该成员保存着一个 task 所申请的所有 pages(page 即 MemoryBlock),最多可以有8192个。在 TaskMemoryManager#allocatePage(...) 中从堆或堆外分配的 page 会被添加到该 pageTable 中。

对 page 地址进行统一编码

通过上面的分析我们知道,page 对应的内存可能来自堆或堆外。但这显然不应该由上层操作者来操心,所以 TaskMemoryManager 提供了只需传入 page 及要访问该 page 上的 offset 就能获得一个 long 型的地址。这样应用者只需操作自该地址起的某一段内存即可,而不用关心这块内存是来自哪。这即是 TaskMemoryManager 提供的 page 地址统一编码,由 TaskMemoryManager#encodePageNumberAndOffset(MemoryBlock page, long offsetInPage): long 实现

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容