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

时间:2013-03-27 11:34:47

标签: java performance scala

enter image description here

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

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

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

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

1 个答案:

答案 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缓冲区大小可能会也可能不会提高性能 - 这取决于程序如何使用缓冲区:

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

尝试分析应用程序并查找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

中有详细说明