论文部分内容阅读
“大数据”时代的到来对于应用进行海量数据处理带来了新的挑战。为此,学术界与工业界设计与实现了多个大数据处理框架以简化大数据处理。为了编程的便捷性与系统的稳定性,当前主流的大数据处理框架如Spark,Hadoop等均使用管控式语言如Scala、Java等进行编程。然而,由于Java虚拟机(JVM)等管控式语言运行时环境需要进行数据抽象、内存管理等,通常对于大数据应用带来了较大的性能开销。同时,由于JVM等提供的额外数据抽象增加了大数据应用与硬件间的语义鸿沟,也使得大数据运行时不能充分挖掘硬件提供的并行性。具体而言,本文在分析以上Java虚拟机以及数据密集型应用运行的过程中,发现了三个不足点:1.为了支持垃圾回收,JVM为运行时代码添加了额外的指令开销。分代式垃圾回收在对年轻代进行回收时,需要遍历老年代到年轻代的引用。这个引用是通过卡表的数据结构完成的。而在程序运行过程中,Java虚拟机需要插入额外的写屏障代码完成卡表操作。2.Java对象布局上存在一些额外开销。为了支持Java虚拟机上的类型安全、垃圾回收等特点,Java对象在布局上需要一个对象头来完成功能。而这个对象头在不使用时将对对象数据的局部性以及访存性能造成影响。3.即时编译器的优化限制性,语义识别不够,不能为上层大数据应用提供较多优化。并且,在Spark框架中,操作还是基于单个元素;不能高效地针对大数据场景进行扩展,也不能使编译器挖掘更多语义进行优化。针对上述问题,本文提出了三个相应的解决方案:1.基于硬件虚拟化技术消除写屏障的额外指令开销。该方案利用垃圾回收中卡表功能与页表功能的相似性。利用硬件虚拟化中客户页表的支持,将页表复用为卡表结构。因此在原有垃圾回收读卡表时,只需要读取页表脏位即可。而由于页表是通过硬件维护,Java虚拟机不再需要生成写屏障。可以在应用运行时省去执行屏障的开销。2.分离式对象内存布局。该布局将对象头和对象数据分开分配在堆中,这样对象头将对对象数据的读写没有直接影响。本文提出了三种运行时对象数据获取方法,并以性能为考量选取其中一种进行实现。使用这种方式,对象数据访问将没有额外开销。当应用只需要使用对象数据时,可以提升对象数据的内存局部性,整体提升访存性能。为了处理分离式对象和正常对象的混合情况,Java堆也被分为正常对象区域和分离式区域,存放对应的对象。3.针对大数据机器学习框架提出超向量的运行时技术。该数据抽象将多个向量聚合在一起,并提供粗粒度的超向量操作。在此基础上,新提供的操作可以针对数据密集计算场景提供优化的语义,如密集计算场景中经常有“多对一”的语义,而使用超向量的操作可以充分挖掘这层语义。超向量还可以促使更加优化的实现,编译器由于获得了更多语言层语义,可以对计算生成更多优化代码,如生成了更多SIMD指令,提升整体的计算性能。以上三个方案均已在JVM以及相应大数据运行时中实现并进行测试。