当我运行IO密集型JVM程序(用Scala编写)时,VisualVM的截图是采用的,堆大小为4 GB,只有2 GB在使用中。 JVM程序使用内存映射文件。
“映射缓冲池”和“直接缓冲池”是什么意思?
那些游泳池似乎非常充实。由于JVM程序使用内存映射文件,如果池更大,我会看到性能提升吗?如果是这样,如何增加它们的大小?
所有映射文件的大小约为1.1GB。
答案 0 :(得分:48)
直接缓冲
direct buffer是一块通常用于将Java连接到OS I / O子系统的内存块,例如,当OS从插槽或磁盘接收数据时写入数据的位置,以及Java可以直接读取。
与OS共享缓冲区比将数据从操作系统复制到Java的内存模型的原始方法要高效得多,后者会使数据受到垃圾收集和低效率的影响,例如迁移时重新复制数据来自伊甸园 - >幸存者 - >终身 - >永久的一代。
在屏幕截图中,您只有一个16KB的直接缓冲区缓冲区。 Java将根据需要增加此池,因此蓝色区域位于块顶部的事实仅仅是一个语句,即所有分配到目前为止的缓冲区内存正在使用中。我不认为这是一个问题。
映射缓冲池
映射缓冲池是Java用于FileChannel个实例的所有内存。
每个FileChannel实例都有一个与OS共享的缓冲区(类似于具有所有效率优势的直接缓冲区)。存储器本质上是文件的一部分的RAM内窗口。根据模式(读取,写入或两者),Java可以直接读取和/或修改文件的内容,操作系统可以直接向磁盘提供数据或将修改后的数据刷新到磁盘。
此方法的其他优点是操作系统可以根据需要将此缓冲区直接刷新到磁盘,例如当操作系统关闭时,操作系统可以从计算机上的其他进程锁定该部分文件
屏幕截图显示12个FileChannel对象使用了大约680MB。同样,Java会增长,这是Scala需要更多(并且JVM可以从操作系统获得额外的内存),因此所有680MB全部使用的事实并不重要。鉴于它们的大小,我觉得该程序已经过优化,可以有效地使用这些缓冲区。
增加映射缓冲池的大小
Java为垃圾收集空间外的FileChannel缓冲区分配内存。这意味着正常的堆大小参数(例如-Xmx
)在这里并不重要
使用map方法设置FileChannel中缓冲区的大小。更改此项将需要更改您的Scala计划
一旦缓冲区达到了KB的10s-100s的阈值大小,增加FileChannel缓冲区大小可能会也可能不会提高性能 - 这取决于程序如何使用缓冲区:
尝试分析应用程序并查找I / O等待(Jprofiler和YourKit擅长此操作)。可能是文件I / O实际上不是问题 - 不要成为premature optimization的受害者。如果I / O等待占总耗用时间的很大一部分,则可能值得尝试更大的缓冲区大小
更多信息
https://blogs.oracle.com/alanb/entry/monitoring_direct_buffers
另请注意,JVM上报告的错误是FileChannel不擅长释放内存。它在Prevent OutOfMemory when using java.nio.MappedByteBuffer
中有详细说明