`
brandNewUser
  • 浏览: 457033 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

项目中Map端内存占用的分析

阅读更多
 
最近在项目中开展重构活动,对Map端内存尽量要省一些,当前的系统中Map端内存最高占用大概3G左右(设置成2G时会导致Java Heap OOM)。虽然个人觉得占用不算多,但是显然这样的结果想要试图去说服一些对内存占用非常挑剔的C++程序员们理由还是不够,于是便通过一定的方式对内存的占用进行了分析,刨根问底。
 
关于运行时内存占用可以参考文章:http://brandnewuser.iteye.com/blog/2113828, 这里采用的是简单的方式,通过反射将内存MemoryCounter的方式计算的内存占用。
 

分析后的内存占用

 

分析后的内存占用峰值,即在我们的报表数据dump之前,就是属于内存占用的峰值。由于报表对象占用的数据非常大,大概1G左右,而且Map的输出中介结果Value格式是BytesWritable,是通过Java序列化方式dump出来的,因此当时的byte[]非常大(甚至可能超出1G)。于是,便采用了拆分报表输出的方式,这样便可以节省一定的内存空间。
 
在分析内存的占用过程中,尽量查找一些不太合理的内存占用,于是我们便查找到其中的一个类,在初始化后,占用500M的内存,这就是其中使用到的org.apache.hadoop.fs.FSDataInputStream,为什么这个类的对象会占用500M内存?
 
代码中初始化org.apache.hadoop.fs.FSDataInputStream后,就立刻占用500M的内存,那么是否这个类我们使用的方式不对?经过我们单独写了一个应用程序的测试(读取的HDFS与上面的环境一致),其内存占用并没有达到哪怕是1M。
 
org.apache.hadoop.fs.FSDataInputStream接收一个InputStream参数,经过打印其具体实现类型,发现为:org.apache.hadoop.hdfs.DFSInputStream,初始化这个类时,内存占用就已经上去了。
     
于是在MemoryCounter中加入日志,将对象size大于100M的对象打印出来,发现有一个byte[]长度为536870912占用内存!
Exceed 100M object[Array]:
byte Exceed 100M object[Array]:
[B Array length: 536870912
 
 
初步计算了一下byte[]长度为536870912,估计为2的29次幂,根据条件打印计算出来的结果,发现:
Start estimate: org.apache.hadoop.mapred.MapTask$MapOutputBuffer: 
Start estimate: org.apache.hadoop.util.QuickSort: 
Start estimate: [B: 
Start estimate: [B: 
Exceed 100M object[Array]: [B
 
于是恍然大悟,是MapOutputBuffer,然后查看了任务配置的参数,果然
mapreduce.task.io.sort.mb=512
 
缓冲区设置占用了512M,也就是2的29次幂,这是需要占用Map端的Java Heap内存,下面就是对这部分的一个学习和回顾。
 

Map Collect 过程分析

 

待每次map函数处理完一对key/value,并产生新的key/value后,就会调用OutputCollector.collect函数输出结果,函数内部首先会调用Partitioner.getPartition()获取纪录的分区号,将<key, value, partition>传递给MapOutputBuffer.collect函数作进一步的处理。
 
MapOutputBuffer内部使用了一个缓冲区暂时存储用户输出数据,当缓冲区的数据达到一定阈值的时候,再将缓冲区的数据写到磁盘上。缓冲区采用的是环形内存缓冲区保存数据(大小为mapreduce.task.io.sort.mb),当达到一定数值(mapreduce.map.sort.spill.percent)后,由线程SpillThread将数据写到一个临时文件中,当所有的数据都处理完成后,对所有的临时文件进行一次合并生成一个最终文件。环形缓冲区使得Map Task的Collect阶段和Spill阶段可以并行地进行。
 
MapOutputBuffer采用了两级索引结构,涉及到3个环形内存缓冲区,三个缓冲区占用内存的总空间为mapreduce.task.io.sort.mb。

 
 
  1. kvoffsets, 偏移量索引数组,用于保存key/value信息在位置索引kvindices中的偏移量,一对key/value需要占用kvoffsets的1个int大小,数组kvindices的3个int大小
  2. kvindices, 位置索引数组,用于保存key/value值在数据缓冲区kvbuffer中的起始位置
  3. kvbuffer,数据缓冲区,用于保存实际的key/value值,默认情况下可以最多使用整个缓冲区的95%
 
以上几个缓冲区读写均采用了典型的生产者消费者模型,MapOutputBuffer的collect方法和MapOutputBuffer的write方法是生产者,spillThread线程是消费者,通过可重入互斥锁的条件变量来完成的。
 
Spill过程是由SpillThread线程完成的,SpillThread线程实际上是缓冲区kvbuffer的消费者,调用sortAndSpill方法将环形缓冲区kvbuffer中的数据写到磁盘上,函数的工作原理如下:
 
  1. 利用快速排序算法对缓冲区kvbuffer的数据进行排序,先按照partition进行排序,然后按照key进行排序。经过排序后,数据以分区为单位聚集在一起,同一分区内的所有数据按照key有序;
  2. 按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件output/spillN.out(N为spill的次数),如果用户设置了Combiner,写入文件之前可能会对每个分区的数据进行一次数据聚集操作;
  3. 将分区数据的元信息写到内存索引数据结构SpillRecord中,每个分区的元信息包括在临时文件的偏移量,压缩前数据大小和压缩后数据大小,如果内存中的索引大小超过1M,将内存索引写到索引文件中output/spillN.out.index中。
 
当所有数据处理完成之后,Map Task会将所有的临时文件合并成一个大的文件,保存到output/file.out.index中。在进行文件合并的过程中,以分区为单位,对于某个分区,采用多轮递归合并的方式:每轮合并io.sort.factor个文件,并将产生的文件重新加入待合并列表中,重复以上过程以最终得到一个大文件。
 
 
 
 
 
 
 
 
  • 大小: 27.7 KB
分享到:
评论

相关推荐

    java中3个json工具分析测试

    2. **内存消耗**:观察在处理相同数据时,各库的内存占用情况。 3. **API易用性**:根据API文档和实际使用体验,评估其学习曲线和使用便捷度。 4. **灵活性**:检查库是否支持自定义序列化策略,如字段忽略、类型...

    arcgis_js_v331_sdk.zip

    V3.31版本对性能进行了优化,降低了页面加载时间和内存占用,提高了地图操作的响应速度。同时,SDK还支持响应式设计,确保在不同设备和浏览器上的良好显示效果。 总结,ArcGIS JavaScript SDK V3.31是GIS开发者的...

    2018.5-2019.1基于FPGA平台的目标检测网络实现 fpga开发.pdf

    由于YOLO计算量大且资源需求较高,项目最终选择了内存需求较小的MTCNN。数据集是根据公交车画面定制的,经过训练,YOLO的mAP(mean Average Precision)达到89%,而MTCNN降低了约30个点。 - **C++端**:实现了神经...

    高德地图api离线化,支持uniapp,web,触屏操作

    在IT行业中,地图API是开发地图相关应用的关键组成部分,它提供了获取地理位置信息、路线规划、导航等功能。本项目聚焦于“高德地图API”的离线化处理,使其能适应多种平台,包括uniAPP、Web以及支持触屏操作的设备...

    ArcGIS API for Javascript 开发教程

    - 分层加载:根据比例尺加载图层,减少初始加载时间和内存占用。 - 范围查询:只加载可视范围内的数据,提高地图滚动时的性能。 - 缓存策略:使用本地缓存或CDN加速地图加载。 8. **最佳实践与案例研究** - ...

    利用java 后台导出Flex DataGrid为Excel

    - 使用内存优化策略,例如在生成Excel时,避免一次性加载所有数据,而是分批处理,减少内存占用。 - 安全性方面,确保数据传输过程中使用HTTPS加密,防止数据泄露。 5. **错误处理与异常处理**: - 编写健壮的...

    包含了Java SE Java学习资料 Java SE学习练习项目源码

    15. **垃圾回收(Garbage Collection)**: Java自动进行内存管理,垃圾回收器会自动回收不再使用的对象所占用的内存,避免内存泄漏。 这份名为"my---java-warehouse-2-master"的压缩包很可能是包含以上知识点的实践...

    前端开源库-panto-stream

    这种特性对于处理大文件、实时数据或者网络传输非常有用,因为它降低了内存占用并提高了性能。Panto Stream正是利用了这个概念,为前端开发者提供了处理流数据的工具。 **Panto Stream的功能特性** 1. **可组合性*...

    js压缩工具

    3. 优化资源管理:更小的文件意味着服务器存储和内存占用减少,有利于大规模应用的部署和维护。 二、JS压缩工具 1. UglifyJS:UglifyJS 是一款功能强大的JavaScript压缩工具,它可以进行变量名混淆、删除未使用的...

    pigeon-optics:Pigeon Optics是一个性能极低的不可缩放玩具数据库,旨在使诸如Auslan Find Sign的小型社区项目的数据处理变得有趣且易于访问。 Pigeon Optics优先考虑低内存利用率,以在任何形式的性能优化上在预算服务器上良好运行。 以MapReduce索引为核心,用户能够创建帐户并编写自己的沙盒javascript mapreduce函数,上传数据集等,只要您不关心写入速度,它就非常强大。

    总的来说,Pigeon Optics是一个专为小规模社区项目设计的数据库系统,它以其低内存占用和MapReduce功能吸引着开发者。虽然在写入性能方面有所妥协,但对于那些重视易用性和低成本运行的项目,Pigeon Optics提供了一...

    Uniapp APP Android 离线SDK 版本号Android-SDK@3.6.18.81676-20230117

    1. 性能优化:可能对SDK进行了内部优化,提高了运行效率,减少了内存占用。 2. 错误修复:修复了之前版本中已知的问题,增强了应用的稳定性。 3. 新功能支持:可能增加了新的API接口或插件,以适应更多应用场景。 4....

    map-compare:openlayers,leaflet,arcgis api,mapbox-gl几个库绘制点、线、面性能对比

    - 内存占用:观察各库在渲染过程中内存的消耗情况,以及随着数据量增加的内存增长趋势。 - 交互响应:评估用户与地图交互(如缩放、平移)时的流畅度和延迟。 - GPU利用率:如果支持WebGL,查看GPU的负载情况,高...

    echarts-5.4.3.zip

    9. **性能优化**:ECharts 5.4.3 版本会继续关注性能优化,如更快的渲染速度、更小的内存占用,以及对大数据量的支持,确保在大数据场景下也能流畅运行。 10. **社区支持与文档**:ECharts 有一个活跃的社区,...

    VC知识库1-12期

    10. **动态链接库(DLL)**:DLL是Windows下的共享库,可以被多个程序同时使用,减少了内存占用和代码重复。VC++提供了创建和使用DLL的方法。 11. **COM(Component Object Model)**:COM是微软的一种二进制兼容性...

    阿里巴巴 面经

    - **MAT**(Memory Analyzer Tool):Eclipse项目的一部分,专门用于内存分析。 **47. Java内存管理及回收算法** - **标记-清除算法**:标记无用对象,然后清理它们。 - **复制算法**:将内存分为两个相等的部分,...

    java课件及源代码

    6. **垃圾回收(Garbage Collection)**:Java自动进行内存管理,当一个对象不再被引用时,垃圾回收器会回收该对象占用的内存空间。 7. **标准库(Java API)**:Java有丰富的标准库,如集合框架(List、Set、Map)...

    黑马面试宝典知识点复习

    - **Nginx优点**:更轻量级、低内存占用、高性能处理静态文件、更好的负载均衡能力。 - **Apache优点**:强大的模块扩展性、支持更多动态内容处理。 #### Httpclient - **定义**:用于发送HTTP请求和接收HTTP响应...

    java的资料进攻初学者

    垃圾回收器会自动检测并回收不再使用的对象所占用的内存。 12. **反射**:反射机制允许程序在运行时动态地获取类的信息(如类名、属性、方法)并调用它们,提供了强大的元编程能力。 13. **注解(Annotation)**:...

    后台服务器开发

    - **awk`与`sed`:文本处理工具,对于日志分析、数据格式化非常有用。 #### 进程与线程概念 深入理解进程与线程的区别,包括: - **CPU调度与上下文切换**:进程间的调度更为昂贵,涉及完整的上下文保存与恢复。 ...

    benchmark:只是一些基准比较

    2. **内存消耗**:分析代码执行时内存的占用情况,比如创建大量对象、缓存策略等,可以帮助优化内存使用。 3. **并发与异步处理**:在多线程或事件驱动的环境中,比较不同并发模型的效率,如Promise、async/await、...

Global site tag (gtag.js) - Google Analytics