什么是Mapped Buffer Pool / Direct Buffer Pool,如何增加它们的大小?

33

enter image description here

当我运行一个使用Scala编写的IO密集型JVM程序时(堆大小为4GB,仅2GB被使用),VisualVM的截图被拍摄。该JVM程序使用内存映射文件。
“mapped buffer pool”和“direct buffer pool”是什么意思?
这些池似乎非常充实。由于JVM程序使用内存映射文件,如果池更大,是否会看到性能提高?如果是这样,如何增加它们的大小?
所有映射文件的大小约为1.1GB。
1个回答

81

直接缓冲区

直接缓冲区通常用于将Java与操作系统I/O子系统进行接口,例如作为操作系统从套接字或磁盘接收数据并写入的地方,Java可以直接从中读取。

与原始方法将数据从操作系统复制到Java的内存模型相比,与操作系统共享缓冲区更加高效,这使得数据不受垃圾回收和低效性的影响,例如数据在从eden -> survivor -> tenured -> 到永久代迁移时的重新复制。

在截图中,您只有一个16KB的直接缓冲区。Java将根据需要扩展此池,因此蓝色区域位于块的顶部仅表示迄今为止分配的所有缓冲区内存都在使用中。我认为这不是问题。

映射缓冲池

映射缓冲池是Java用于其FileChannel实例的所有内存。
每个FileChannel实例都有一个与操作系统共享的缓冲区(类似于直接缓冲区,具有所有效率优势)。该内存本质上是文件一部分的RAM窗口。根据模式(读取、写入或两者兼备),Java可以直接读取和/或修改文件内容,操作系统可以直接提供数据或将修改后的数据刷新到磁盘。
此方法的其他优点是,操作系统可以根据需要直接将此缓冲区刷新到磁盘,例如在操作系统关闭时,并且操作系统可以锁定该文件的那部分以防止其他计算机进程访问。
屏幕截图显示您使用了12个FileChannel对象的约680MB。同样,如果Scala需要更多空间,Java会增加它(并且JVM可以从操作系统获取额外的内存),因此所有680MB都在使用中并不重要。鉴于其大小,我认为程序已经被优化以有效地使用这些缓冲区。
增加映射缓冲池的大小
Java为FileChannel缓冲区分配内存,这意味着正常的堆大小参数,如-Xmx在这里不重要。
在FileChannel中,缓冲区的大小是通过map方法设置的。更改这个大小需要更改您的Scala程序。
一旦缓冲区达到阈值大小(大约10-100 KB),增加FileChannel缓冲区大小可能会增加性能,也可能不会 - 这取决于程序如何使用缓冲区:
  • : 如果文件只被从头到尾读取一次: 几乎所有的时间都是在等待磁盘或处理算法。
  • 可能: 然而,如果算法经常扫描文件并多次重复访问部分内容,则增加缓冲区大小可能会提高性能:
    • 如果修改或写入文件,则较大的缓冲区可以将更多的写入合并为单个刷新。
    • 如果读取文件,则操作系统很可能已经缓存了文件(磁盘缓存),因此任何收益可能都很小。令人困惑的是,增加JVM的大小可能会通过缩小有效的磁盘缓存大小而降低性能。
    • 无论如何,应用程序必须专门编码才能获得任何好处,例如通过将自己的逻辑记录指针实现到缓存中。
尝试对应用程序进行性能分析,并查找I/O等待(Jprofiler和YourKit在此方面表现不错)。也许文件I/O实际上并不是问题所在——不要成为过早优化的受害者。如果I/O等待占总运行时间的显著部分,则尝试使用更大的缓冲区大小可能值得一试。 更多信息

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

请注意,有一项关于JVM的bug报告称FileChannel不擅长释放内存。详见Prevent OutOfMemory when using java.nio.MappedByteBuffer


1
这是我在stackoverflow上迄今为止收到的最棒的答案。非常感谢! - user972946

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接