close
当前位置: SmartTimes > 硬科技 > 技术 >

Java *支持英特尔®傲腾™DC持久性存储器

介绍

在本文中,我们描述了各种机制,除了Java *应用程序的动态随机存取内存(DRAM),您还可以通过这些机制将Intel®Optane™DC永久内存用作易失性内存。我们首先简要介绍Java内存管理和Intel®Optane™DC持久性内存模块OS支持,然后深入探讨Java使用机制。

Java *内存管理

Java虚拟机(JVM)提供了一个托管运行时环境,用于在目标平台上执行Java程序。Java程序被编译为平台无关的字节码,并整理为jar文件或模块,并使用JVM在目标平台上执行。
内存管理是JVM提供的一项关键功能。JVM代表应用程序管理一块称为Java堆的内存。应用程序使用新关键字创建的所有Java对象均由JVM在Java堆上分配。Java应用程序也不需要释放分配的内存。JVM使用称为垃圾收集的过程自动确定哪些对象未被使用,并从这些对象中回收内存。
Java堆的默认大小在不同的JVM实现中有所不同,并且通常根据系统中的可用内存来确定。您还可以在JVM命令行上配置Java堆。
OpenJDK *是Java平台标准版(SE)运行时的领先免费和开源实现,已为业界广泛采用。Java SE的参考实现也基于OpenJDK。

 英特尔®傲腾™DC永久性内存

英特尔Optane DC永久内存代表了专门为数据中心使用而设计的新型内存和存储技术。它提供了高容量,可负担性和持久性的空前组合。通过扩展负担得起的系统内存容量,客户可以使用支持此类新型内存的系统,通过将更多数据移至并保持更靠近处理器的位置并最大程度地减少从系统存储中获取数据的较高延迟,从而更好地优化工作负载。
具有Intel Optane DC永久性内存模块的Intel®平台可以根据应用程序要求以不同的模式进行配置。在“内存模式”下,永久内存作为系统的整个可寻址内存公开,而DRAM充当高速缓存层。为了更好地控制数据放置,可以在App Direct模式下配置Intel平台,其中DRAM和永久性内存模块均作为可寻址内存公开给应用程序。您可以在文章为下一代内存做准备中找到有关配置英特尔®持久性内存的更多详细信息。
本文档中显示的所有用例和示例均在App Direct模式下使用Intel Optane DC永久性内存模块,以提供大容量和低成本的易失性内存。

操作系统支持

诸如Linux *和Windows *的操作系统(OS)使用直接访问(DAX)模式通过特殊的文件系统公开持久性内存。DAX模式使文件系统(例如NTFS,EXT4和XFS)将持久性内存安装为文件系统。它提供了应用程序直接访问Intel Optane DC永久性内存模块的功能,从而绕过了操作系统页面缓存,直接从可字节寻址的永久性内存模块中进行读取和写入。安装DAX的文件系统中的文件映射(例如,在Linux中使用mmap)将直接将Intel Optane DC永久性内存模块中的页面映射到用户空间。
作为一个DAX文件系统在更详细的描述安装使用永久内存模块的过程NDCTL入门指南Linux和创建Windows开发环境在pmem.io.

Java *中的使用场景

您可以在内存或App Direct模式下为Java应用程序使用Intel Optane DC永久内存。对于“内存”模式使用,您只需要配置底层操作系统即可将Intel Optane DC永久内存模块公开为系统的整个可寻址内存,而DRAM则充当高速缓存。您无需对Java应用程序或JVM配置进行任何更改即可利用内存模式。在此配置中,所有JVM,即时(JIT)编译的Java应用程序代码,元数据,Java堆栈和Java堆都驻留在持久性内存中。
应用程序直接模式,其中DRAM和Intel Optane DC永久性内存模块都作为可寻址内存公开给应用程序,使您可以控制更多。在这种模式下,您可以继续在DRAM中保留JVM,JIT编译的Java应用程序代码,堆栈和元数据,并以更精细的粒度在持久性内存中托管整个Java堆,部分Java堆或Java对象。
英特尔Optane DC持久性存储器具有与DRAM不同的延迟和带宽特性,要使用的最佳配置取决于您的Java应用程序特性和需求。在以下各节中,我们描述如何在Java应用程序的App Direct模式下以不同的粒度级别使用持久性内存。

持久内存的整体堆

JVM使用Java堆上的新关键字分配应用程序创建的所有Java对象。要将Java堆托管在Intel Optane DC永久内存上,您将需要使用OpenJDK中添加的新功能。当前,此功能可作为JDK 11的OpenJDK二进制文件的一部分使用。要启用此功能,请使用命令行标志-XX:AllocateHeapAt,它指示JVM在持久性内存上分配应用程序的Java堆。该标志采用安装永久性存储器的路径,并使用它创建一个临时文件以用作Java堆的后备文件。如下图所示:
堆映射图
让我们在Linux上更详细地看一个例子。
  1. Intel Optane DC永久性内存模块安装在/ mnt / pmem1:
    1 # sudo mount –v | grep /pmem<font></font>
     
    2 /dev/pmem1 on /mnt/pmem1 type ext4 (rw,relatime,dax)<font></font>
     
  2. 我们运行MyApp类,并在Intel Optane DC永久内存上分配了128 GB的堆,如下所示:
    1 # java -version<font></font>
     
    2 openjdk version "11.0.2" 2019-01-15<font></font>
     
    3 OpenJDK Runtime Environment 18.9 (build 11.0.2+9)<font></font>
     
    4 OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)<font></font>
     
    5 <font></font>
     
    6 # java -Xmx128g -XX:AllocateHeapAt=/mnt/pmem1 MyApp &<font></font>
     
    7 [1] 13068<font></font>
     
  3. Java进程的进程映射文件显示映射到Intel Optane DC永久性内存模块的7ef394000000-7f1394000000范围内的128 GB内存:
    1 # cat /proc/13068/maps | grep heap<font></font>
     
    2 ...<font></font>
     
    3 7ef394000000-7f1394000000 rw-s 00000000 103:01 11 /mnt/pmem1/jvmheap<font></font>
     
    4 ...<font></font>
     
请注意,由JVM管理的其他内存块(例如JIT编译的Java应用程序代码,堆栈和元数据)将继续在DRAM中分配。该标志不会更改其余JVM的行为。现有的与堆和垃圾回收相关的标志(例如-Xmx,-Xms等)具有与以前相同的语义。

永久内存部分堆

Java内存管理将堆分为两代:老的和老的。新分配在年轻一代中执行,对象保留在年轻一代中几个垃圾回收(GC)周期。一个对象在经历了几次GC循环后,就移入了旧的一代。一旦移至旧世代,该对象将停留在那里直到无法到达并由GC收集。
尽管每个应用程序的行为各不相同,但是与上一代相比,年轻一代中的内存访问通常更高。同时,年轻一代通常只占总堆的一小部分。这意味着应用程序可以在Intel Optane DC持久性内存中分配大量的旧一代,而在DRAM中放置较小的一代。
要仅在持久性内存中托管旧版Java堆,您将需要在OpenJDK中使用一项新的实验性功能。当前,此功能可作为JDK 12的OpenJDK二进制文件的一部分使用。要启用该功能,请使用命令行标志-XX:AllocateOldGenAt,它指示JVM在持久性内存上分配旧版的Java堆。年轻一代继续分配在DRAM上。下图描述了此映射:
堆映射图
让我们看一下Linux上的示例:
  1. 和以前一样,Intel Optane DC永久内存安装在/ mnt / pmem1:
    1 # sudo mount -v | grep /pmem<font></font>
     
    2 /dev/pmem1 on /mnt/pmem1 type ext4 (rw,relatime,dax)<font></font>
     
  2. 我们将MyApp类与旧一代放在持久性内存中一起运行:
    1 # java -version<font></font>
     
    2 openjdk version "12" 2019-03-19<font></font>
     
    3 OpenJDK Runtime Environment (build 12+33)<font></font>
     
    4 OpenJDK 64-Bit Server VM (build 12+33, mixed mode, sharing)<font></font>
     
    5 <font></font>
     
    6 # java –XX:+UseG1GC -Xmx128g –Xmn16g –XX:+UnlockExperimentalVMOptions -XX:AllocateOldGenAt=/mnt/pmem1 MyApp<font></font>
     
G1和ParallelOld垃圾收集算法支持此选项。该功能保持了GC的人体工程学,并可以动态调整堆世代的大小。有关此功能的更多详细信息,请参见发行说明。

永久内存上的DirectByteBuffer

如果要为Java应用程序使用比整个堆或部分堆更好的粒度的持久性内存,则可以使用DirectByteBuffer对象,并在Intel Optane DC持久性内存上分配它们。从JDK 1.4开始,就可以使用ByteBuffer。这可以通过下面描述的两种机制来实现。

使用FileChannel的DirectByteBuffer

甲DirectByteBuffer可以通过映射文件的区域直接进入存储器中创建。您可以使用FileChannel类提供的功能将DirectByteBuffer映射到Intel Optane DC永久内存。
以下代码演示了这种方法:
01 import java.nio.channels.FileChannel;<font></font>
 
02 import java.nio.channels.FileChannel.MapMode;<font></font>
 
03 import java.nio.ByteBuffer;<font></font>
 
04 import java.nio.ByteBuffer;<font></font>
 
05 import java.io.RandomAccessFile;<font></font>
 
06 <font></font>
 
07 Class OffHeap {<font></font>
 
08   public static void main(String[] args) {<font></font>
 
09     // Intel DCPMM is mounted as a DAX filesystem at /mnt/pmem<font></font>
 
10     // Open a file on Intel DCPMM for read/write<font></font>
 
11     RandomAccessFile pmFile = new RandomAccessFile("/mnt/pmem/myfile", "rw");<font></font>
 
12 <font></font>
 
13     // Get the corresponding file channel<font></font>
 
14     FileChannel pmChannel = pmFile.getChannel();<font></font>
 
15 <font></font>
 
16     // Maps a 1 GB region in DAX file into memory<font></font>
 
17     ByteBuffer pmembb = pmChannel.map(MapMode.READ_WRITE, 0, (1 << 30) - 1);<font></font>
 
18 <font></font>
 
19 <font></font>
 
20     // Perform writes<font></font>
 
21     for (int i = 0; i < (1<< 31)-1; i++) {<font></font>
 
22        pmembb.put(i, (byte)(i&0xff));<font></font>
 
23 <font></font>
 
24     // Perform reads and verify<font></font>
 
25     for (int i = 0; i < (1<< 31)-1; i++) {<font></font>
 
26        if (pmembb.get(i) != (byte)(i&0xff)) {<font></font>
 
27           System.out.println("Erorr at index:" + i);<font></font>
 
28        }<font></font>
 
29     }<font></font>
 
30 <font></font>
 
31     // Truncate the file to 0 size<font></font>
 
32     pmchannel.truncate(0);<font></font>
 
33 <font></font>
 
34     // Close the file channel<font></font>
 
35     pmchannel.close();<font></font>
 
36 <font></font>
 
37     // Close the file<font></font>
 
38     pmfile.close();<font></font>
 
39   }<font></font>
 
40 }<font></font>
 
在上面的示例中,对ByteBuffer的put()和get()调用执行直接写操作,并将其读入持久性内存。请注意,您必须使用模式READ_WRITE或READ。MapMode.PRIVATE不提供直接映射到持久性内存。

使用Java本机接口(JNI)的DirectByteBuffer

OpenJDK还支持通过Java本机接口(JNI)从本机代码创建DirectByteBuffer。您可以使用JNI 在持久性内存上分配DirectByteBuffer。JNI代码可以使用诸如Memkind 3之类的库。Memkind管理各种内存,包括Intel Optane DC永久内存,并支持诸如memkind_alloc()之类的调用来分配不同大小的内存块。“ 使用Memkind管理大型易失性内存容量”一文介绍了如何将Memkind与英特尔®傲腾™DC持久性内存一起使用。JNI有一种称为NewDirectByteBuffer 4的机制,它可以将本机分配的内存持久性内存包装在DirectByteBuffer用于从Java代码访问。

摘要

在本文中,我们研究了当今可用的各种方式,以Java应用程序的App Direct模式使用Intel Optane DC永久内存。不同的机制为用户提供了功能强大的工具,可以以不同的粒度级别控制数据在持久性内存中的放置。使用的最佳配置取决于应用程序的特性和需求。

关于作者

Kishor Kharbas是Intel的软件工程师。他于2011年加入英特尔,一直致力于为英特尔服务器平台进行Java虚拟机优化。
Sandhya Viswanathan是Intel的一名软件工程师,在编译器和软件开发工具方面拥有25年以上的行业经验。她于2008年加入英特尔,一直致力于为英特尔服务器平台进行Java虚拟机优化。她是Java工程团队的技术负责人,致力于Java JIT编译器,运行时和GC优化。

(责任编辑:ioter)

用户喜欢...

英特尔®OpenVINO™工具包预览版对Raspbian *上的英特尔®神经计算棒2的支持

介绍 如发行说明中所述,英特尔OpenVINO工具包2018 R5发行版引入了对Raspbian * 9的预览支持,以作为英特尔Movidius神经计算棒和英特尔神经计算棒2目标的主机。本文提供了初步信息和资源,用于在...


英特尔®Stratix®10 TX信号完整性开发套件

介绍 英特尔Stratix10 TX信号完整性(SI)开发套件提供了完整的设计环境,其中包括用于开发英特尔Stratix 10 TX FPGA设计的硬件和软件。 您可以使用此开发套件执行以下操作: 对于H-Tile评估收发器...


Stratix 10 GX信号完整性开发套件

介绍 英特尔的Stratix10 GX信号完整性开发套件提供了一个完整的设计环境,其中包括您需要开始使用Stratix 10 GX FPGA的性能和功能来满足您的设计需求所需的所有硬件和软件。 图1. Stratix 10 GX信号...


用更快、更环保、更稳定可靠的数据中心支持云计算

数据中心必须通过提高服务器虚拟化水平来响应云计算所驱动的容量需求。 虚拟化将多个服务器整合到一个物理处理器中,多个应用在其中并行运行,使服务器的利用率提升高达90%。...


Jaspersoft BI 系统基于世界上最流行的开源商业智能 JAVA 报表库及图形化的报表设计工具

Jaspersoft BI 系统基于世界上最流行的开源 JAVA 报表库及图形化的报表设计工具-JasperReport和iReport,目的是为客户提供综合的、全系列的 BI 产品。该系统根据 BI 系统的不同需求,提供即时报表、交互式查询及报表、仪表盘、产品报表、数据分析,以及数据整合等多种报表功能;该系统既可以单独部署使用,也可以集成到用 户的其它系统中而共享通用的元数据、安全信息、仓库对象及计划任务等;该系统同时提供完整的 API 供用户定制、功能扩展以及跟其它系统无缝集成。...