flink-1.21.1源码阅读之内存管理


  Flink的内存管理设计的主要目标是不进行jvm的full-gc,甚至尽量少的进行young-gc,所以如果不发生full-gc,那么基本不会出现oom.
  Spark的内存管理也是借鉴了flink的内存设计,所以目前为止,在大数据计算领域,可以说flink的内存设计是最好的,也是最具有代表性的.

1 flink内存设计的显著之处

  Flink的内存设计可以作为大数据计算的参考标准,目前很多都按照这个思路进行的,比如spark.

1.1 分页内存设计

  Flink的分页是默认32k大小的,底层只是一个字节数组,但是这个分页在jvm堆上是老年代对象.
  由于在jvm的堆上,内存页是字节数组,这个数组内的内容是可以更改的,同时这些内存页的数量也是固定的,因此在jvm堆内老年代中很大一部分对象是固定不变的,所以如果发生full-gc,那么一定是由于从新生代移动到老年代的对象造成的.
  如此一来控制full-gc就变的容易和清晰很多,客户在新生代中创建的对象很大一部分都被flink自身的序列化机制存入了内存页中,那些非序列化的对象大小通常也不会超过某个限制,所以只要控制新生代中由客户创建的非序列化对象数量即可,这就变得简单很多.

1.2 自定义序列化

  Flink处理的主要数据对象都是经过序列化的,然后以字节的形式存入内存页中,所以客户创建的对象大部分都被保存在了老年代中.
  这种序列化机制非常高效,使得内存占用非常低,同时由于是保存在数组中,老年代中的对象也很稳定,发生full-gc的次数很少,几乎不发生.而基于这些字节数组的计算页没有产生新的对象,因此在计算过程中,内存使用也是固定的,这种好处显而易见.

1.3 直接操作二进制数据

  正是由于flink可以直接对序列化后的字节进行计算,所以内存使用和计算效率非常高.
  Flink基于字节的计算主要有分组,排序和连接.分组就是针对groupby的操作,排序就是针对sort的操作,连接就是针对join的操作.其具体使用了二进制数据的位来操作,和指针的操作类似,这里不再展开.
  二进制数据的操作结果依然是字节,同样保存在内存页中,只有在需要的时候才会序列化位对象,而序列化无疑是消耗cpu的主要操作,因此flink的计算避免了很多的序列化.

2 源码参照

  这里在设计上也比较简洁,负责管理内存的是MemoryManager类,负责具体的内存页实现的是MemorySegment类.

2.1 MemoryManager

  这里flink的内存管理主要是MemoryManager来实现的,首先看一下具体的内存页等属性设置
在这里插入图片描述
  可以看到,默认页大小为32k,最小位4k,再看一下唯一的构造器
在这里插入图片描述
  首先是总大小,其次是设置的页大小,两者相除得到页数,分配的和保留的页都记录在map里.
  最后,看一下该类的主要方法
在这里插入图片描述
  可见,主要有分配页,计算页大小,释放页,和普通的内存管理没有什么大的不同.

2.2 MemorySegment

  首先看一下该类的属性设置
在这里插入图片描述
  从属性可以看到为两种类型,一种是jvm堆内内存,一种是堆外内存.堆内内存使用字节直接 表示大小,堆外使用地址表示大小.
  因此对应两种构造器,堆内内存构造器
在这里插入图片描述
  堆外内存构造器
在这里插入图片描述

3 结论

  Flink内存设计非常简洁清晰,使用字节组来表示内存页,使用map来记录页的使用,这些在大数据的计算中具有非常大的参考价值.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值