什么是映射缓冲池/直接缓冲池以及如何增加它们的大小?

21 java performance scala

在此输入图像描述

VisualVM的截图是在我运行IO密集型JVM程序(用Scala编写)时进行的,堆大小为4 GB,只有2 GB在使用中.JVM程序使用内存映射文件.

"映射缓冲池"和"直接缓冲池"是什么意思?

那些游泳池似乎非常充实.由于JVM程序使用内存映射文件,如果池更大,我会看到性能提升吗?如果是这样,如何增加他们的规模?

所有映射文件的大小约为1.1GB.

And*_*ock 52

直接缓冲

直接缓冲液是通常用于接口的Java到OS的I/O子系统,例如作为其中的OS,因为它从插座或磁盘,并从其中Java可以直接读取接收写入数据的地方的存储器中的块.

与操作系统共享缓冲区比将数据从操作系统复制到Java的内存模型的原始方法要高效得多,后者会使数据受到垃圾收集和低效率的影响,例如从伊甸园迁移时重新复制数据 - >幸存者 - >终身 - >给永久的一代.

在屏幕截图中,您只有一个16KB的直接缓冲区缓冲区.Java将根据需要增加此池,因此蓝色区域位于块顶部的事实仅仅是到目前为止分配的所有缓冲区内存都在使用的语句.我不认为这是一个问题.

映射缓冲池

映射的缓冲池是Java用于其FileChannel实例的所有内存.

每个FileChannel实例都有一个与OS共享的缓冲区(类似于具有所有效率优势的直接缓冲区).存储器本质上是文件的一部分的RAM内窗口.根据模式(读取,写入或两者),Java可以直接读取和/或修改文件的内容,操作系统可以直接向磁盘提供数据或将修改后的数据刷新到磁盘.

此方法的其他优点是OS可以在其认为合适时将此缓冲区直接刷新到磁盘,例如当OS关闭时,OS可以从计算机上的其他进程锁定该部分文件.

屏幕截图显示12个FileChannel对象使用了大约680MB.同样,Java会增长,这是Scala需要更多(并且JVM可以从操作系统获得额外的内存),因此所有680MB全部使用的事实并不重要.鉴于它们的大小,在我看来,该程序已经被优化以有效地使用这些缓冲区.

增加映射缓冲池的大小

Java为垃圾收集空间之外的FileChannel缓冲区分配内存.这意味着正常的堆大小参数-Xmx在这里并不重要

使用map方法设置FileChannel中缓冲区的大小.更改此项将需要更改您的Scala计划

一旦缓冲区达到KB的10s-100s的阈值大小,增加FileChannel缓冲区大小可能会或可能不会提高性能 - 这取决于程序如何使用缓冲区:

  • :如果文件从头到尾精确读取一次:几乎所有时间都在等待磁盘或处理算法
  • 可能:但是,如果算法经常多次扫描文件重访部分,则增加大小可能会提高性能:
    • 如果修改或写入文件,则较大的缓冲区可以将更多写入合并到单个刷新中.
    • 如果读取文件,操作系统可能已经缓存了文件(磁盘缓存),因此任何增益都可能是微不足道的.不正确地增加JVM的大小可能会通过缩小有效磁盘高速缓存大小来降低性能
    • 在任何情况下,应用程序都必须经过特殊编码才能获得任何好处,例如通过在缓存上实现自己的逻辑记录指针.

尝试分析应用程序并查找I/O等待(Jprofiler和YourKit擅长于此).可能是文件I/O实际上不是问题 - 不要成为过早优化的受害者.如果I/O等待是总耗用时间的重要部分,则可能值得尝试更大的缓冲区大小

更多的信息

https://blogs.oracle.com/alanb/entry/monitoring_direct_buffers

另请注意,JVM上报告的错误是FileChannel不擅长释放内存.在使用java.nio.MappedByteBuffer时,它在Prevent OutOfMemory中有详细说明