Flink 内存管理机制

序:

Flink的内存管理机制也是Flink的一大亮点。Flink在JVM内部实现了自己的内存管理。

 

一、MemorySegment

MemorySegment是Flink内存管理的核心,是Flink的内存抽象。默认情况下,一个MemorySegment可以被看做是一个32KB大小的内存块抽象。这个内存即可以是JVM里的一个byte[],也可以是堆外内存,这个可以从MemorySegment的构造方法中看出来。

Flink为MemorySegment提供了两个实现类,分别是org.apache.flink.core.memory.HeapMemorySegment和org.apache.flink.core.memory.HybridMemorySegment。HeapMemorySegment用于管理heap memory,而HybridMemorySegment可以作用于on-heap,off-heap direct或者off-heap unsafe。这样就使得HeapMemorySegment的作用被HybridMemorySegment替代了。事实上,确实如此,HeapMemorySegment已经被打上了unsed标识,说明Flink已经不再用它了。

 

二、NetworkBufferPool和LocalBufferPool

NetworkBufferPool是在TaskManager启动的时候创建的,具体源码涉及到 :TaskManagerRunner的runTaskManager方法 创建TaskManagerRunner实例,然后再运行startTaskManager,在startTaskManager中会调用TaskManagerServices.fromConfiguration方法,去创建NetworkBufferPool。所以NetworkBufferPool在每个TaskManager上只有一个,负责所有子Task的内存管理。其 实例化时,就会获取所有可由它管理的内存。

NetworkBufferPool是一个总的管理TaskManager内存的类。而TM上,每个task的内存隔离是通过LocalBufferPool来实现的,每个Task都有一个和其他Task隔离的LocalBufferPool。NetworkBufferPool负责分配MemorySegments给各个LocalBufferPool,LocalBufferPool在初始化的时候就需要有numberOfRequiredMemorySegments 个MemorySegments,这个是由ResultPartition的subpartition决定。LocalBufferPool就是来管理各自task上的MemorySegments的。可以看下这个类中所拥有的一些属性


	/** Global network buffer pool to get buffers from. */
	private final NetworkBufferPool networkBufferPool;

	/** 该内存池需要的最少内存片数目*/
	/** The minimum number of required segments for this pool. */
	private final int numberOfRequiredMemorySegments;

	/**
	 *
	 * 当前已经获得的内存片中,还没有写入数据的空白内存片
	 * The currently available memory segments. These are segments, which have been requested from
	 * the network buffer pool and are currently not handed out as Buffer instances.
	 *
	 */
	private final ArrayDeque availableMemorySegments = new ArrayDeque();

	/**
	 *
	 * 注册的所有监控buffer可用性的监听器
	 * Buffer availability listeners, which need to be notified when a Buffer becomes available.
	 * Listeners can only be registered at a time/state where no Buffer instance was available.
	 */
	private final ArrayDeque registeredListeners = new ArrayDeque<>();

	/** 能给内存池分配的最大分片数*/
	/** Maximum number of network buffers to allocate. */
	private final int maxNumberOfMemorySegments;

	/** 当前内存池大小 */
	/** The current size of this pool. */
	private int currentPoolSize;

	/**
	 * 所有经由NetworkBufferPool分配的,被本内存池引用到的(非直接获得的)分片数
	 * Number of all memory segments, which have been requested from the network buffer pool and are
	 * somehow referenced through this pool (e.g. wrapped in Buffer instances or as available segments).
	 */
	private int numberOfRequestedMemorySegments;

 

 

介绍完这个三个概念,就可以对Flink的内存管理有个初步的意识。NetworkBufferPool 负责管理和分配MemorySegment给每个Task的LocalBufferPool,而数据则是序列化成byte[]或者堆外内存,存放在这个MemorySegment中。而MemorySegment则是在TaskManager启动的时候就已经初始化好了,不需要再次去申请。当不需要这块数据的时候,可以直接调用MemorySegment的free或者release方法。release方法是对free的一层封装,其实内部使用的还是free,去释放内存。

这样就可以实现自主的内存管理了。对于堆内存来说,直接获取所有内存并放入老年代,并令用户对象只在新生代存活,可以极大的减少Full GC。

你可能感兴趣的:(flink,Flink,内存管理机制)