存储器只是计算机分层存储系统中cpu附近的存储介质。
1.spark在内存中运行?
2.如何管理里面存储的内容?
3.spark是用jvm语言编写的,例如java和scala。没有像c语言那样释放内存的明确应用程序。如何管理记忆?
4.我们应该如何设置关于记忆的火花参数?
一,内存模型
古代神曾经告诉过我们这个神秘的公式:程序=算法+数据。
1.1什么是内存模型?
内存模型告诉我们如何划分内存以及如何合理地使用内存。
首先,根据大神的公式我们想要保存的东西,我们分析这个:
数据:这是我们的代码运行的数据,例如人的数据(年龄,位置等)或输入的值。这些可以在运行时将一些要计算的数据加载到内存中。
算法:它是操作数据的逻辑,表达式是代码或编译指令。当然,它会运行,它将依赖于部分内存来存储程序计数器(代码执行到句子),函数调用栈和运行时所需的其他数据。总而言之,它是执行数据操作逻辑所必需的内存。
现在我们可以将需要存储的内容划分为数据区和执行区。
二,火花记忆模型
2.1火花很快
我们都知道spark比mapreduce计算更快,因为它基于内存。它不需要在每次计算时写入磁盘,然后将其读出以进行下一次计算。 Spark直接使用内存作为数据的临时存储介质。因此mapreduce不强调内存管理,而spark需要管理内存。
2.2火花管理记忆
系统区域:Spark需要一定的空间来运行自己的代码。
用户区:我们自己编写的一些代码,比如udf,也需要一定的空间来运行。
存储区域:spark的任务是操纵数据。 Spark可以将数据快速存储在内存中,这些数据也需要空间。
执行区:火花操作数据的单位是分区。 spark执行诸如shuffle,join,sort和aggregation之类的操作。需要将分区加载到内存中进行计算,这也适用于某些内存。2.3火花记忆模型
上图是火花存储器分区的映射。
我们从下到上解释:
1级:整个激励器使用的记忆
第2层:分为jvm内存和jvm外部内存,其中jvm内存中的yarn指的是所请求容器的内存。
第3层:对于spark,内存分为jvm堆和memory-head,堆外
jvm堆中的下一层
memoryOverhead:相应的参数是spark.yarn.executor.memoryOverhead此内存用于虚拟机开销,内部字符串和一些本地开销(例如Python需要的内存)。实际上,它是额外的内存,并且spark不管理这个内存。
堆外:由spark.memory.offHeap.size参数指定的内存(广义上指的是所有堆外)。这部分内存应用和发布是直接进行的,没有jvm控件,所以没有GC,火花分为存储和执行两部分,第五层由spark共同管理。
第4层:jvm堆中的内存分为三个部分。
reservedMemory:预留内存300M,用于确保火花的正常运行
其他内存:用于spark内部的一些元数据,即用户的数据结构,以防止导致内存估计不足的内存缓冲区,以及占用大空间的缓冲区。
内存派系:内存的主要控制,由参数spark.memory.fraction控制。
第5层:分为存储和执行。两者的大小由参数spark.memory.storageFraction控制,但是
执行:用于spark的计算:shuffle,sort,aggregation等。如果计算内存不足,计算中使用的内存将从存储部分借用。如果仍然不够,它将溢出到磁盘。
存储:主要用于rdd缓存。如果执行借用内存,它可能会牺牲自己的丢弃缓存来提供执行。存储也可以从执行中借用内存,但执行不会牺牲自己。三,源级
3.1总体架构
内存应用和发布(绿色):
看看上面的绿色图片,它是内存应用程序和发布模块。 MemoryAllocator接口负责内存请求。有两个子类实现分别负责堆内存和堆外内存。
内存池(粉红色):
MemoryPool内存池有两个子类,用于管理执行内存和存储内存。您可以看到两个内存池的应用程序方法的参数之间存在明显差异。执行存储器主要面向任务,存储存储器主要用于块,用于rdd缓存。
统一内存管理:
MemoryManager负责记录内存消耗并管理四个内存池。子类UnifiedMemoryManager负责统一执行内存和存储内存,并实现相互借用等功能。
MemoryManager使用场景
一个是用于管理存储的BlockManager,另一个是运行Task的内存使用情况。它主要使用执行程序,并且shuffle是外部排序的。
3.2如何实现内存应用程序发布。
Spark是用scala和java实现的。管理内存应用程序的发布没有api。 spark如何使用这些jvm语言来管理内存?
我们来看看源代码
//HeapMemoryAllocator.scalaprivate final Map bufferPoolsBySize=new HashMap();
... public MemoryBlock allocate(long size)抛出OutOfMemoryError {
......以上是一些记忆的判断...... long [] array=new long [numWords]; //以上是非常重要的
MemoryBlock memory=new MemoryBlock(array,Platform.LONG_ARRAY_OFFSET,size); if(MemoryAllocator.MEMORY_DEBUG_FILL_ENABLED){
Memory.fill(MemoryAllocator.MEMORY_DEBUG_FILL_CLEAN_VALUE);返回记忆;
}
HeapMemoryAllocator可以看到上面的源代码片段,实际的内存应用程序是这个代码:new long [numWords];是一个占用内存的新数组,用MemoryBlock包装。 bufferPoolsBySize这是为了防止内存频繁请求和释放缓冲区。
接下来,让我们看看off-heap如何应用于内存。
//UnsafeMemoryAllocator
Public MemoryBlock allocate(long size)抛出OutOfMemoryError {long address=Platform.allocateMemory(size);
MemoryBlock memory=new MemoryBlock(null,address,size); if(MemoryAllocator.MEMORY_DEBUG_FILL_ENABLED){
Memory.fill(MemoryAllocator.MEMORY_DEBUG_FILL_CLEAN_VALUE);
返回记忆;
}
Offheap与C语言相同,可以使用api直接应用。这部分内存需要自己管理,没有jvm的控制,没有内存回收机制。