了解Java缓冲池

了解Java缓冲池

缓冲池空间位于垃圾收集器管理的内存之外。 这是分配本地堆外内存的一种方法。 使用缓冲池有什么好处? 为了回答这个问题,让我们首先了解什么是字节缓冲区。

字节缓冲区

非直接缓冲区

ByteBuffer类附带了java.nio包。 它允许我们分配直接和非直接字节缓冲区。 非直接字节缓冲区没有什么特别的-它们是由ByteBuffer.allocate()ByteBuffer.wrap()工厂方法创建的HeapByteBuffer的实现。 就像该类的名称所暗示的那样,它们是堆上字节缓冲区。 那么,在Java堆空间上分配所有缓冲区会不会更容易? 为什么有人需要在本机内存中分配某些内容? 要回答这个问题,我们需要了解操作系统如何执行I / O操作。 任何读或写指令都在连续的字节序列存储区上执行。 那么byte[]是否在堆上占据了连续的空间? 从技术上讲这很有意义,但是JVM规范没有这样的保证。 更有趣的是, 规范甚至不能保证堆空间本身是连续的! 尽管JVM不太可能将一维原语数组放置在内存中的不同位置,但是Java堆空间中的字节数组不能直接用于本机I / O操作。 必须在每次I / O之前将其复制到本机内存,这当然会导致明显的低效率。 因此,引入了直接缓冲区。

直接缓冲

直接缓冲区是与Java共享的本机内存块,您可以从中执行直接读取。 可以使用ByteBuffer.allocateDirect()工厂方法创建DirectByteBuffer的实例。 字节缓冲区是执行I / O操作的最有效方法,因此,它们在许多库和框架中使用,例如在Netty中。

内存映射缓冲区

直接字节缓冲区也可以通过将文件区域直接映射到内存中来创建。 换句话说,我们可以将文件的区域加载到可以稍后访问的特定本机内存区域。 您可以想象,如果我们需要多次读取文件内容,它可以显着提高性能。 借助内存映射文件,后续读取将使用内存中文件的内容,而不是每次需要时都从光盘加载数据。 MappedByteBuffer可以通过创建FileChannel.map()方法。

内存映射文件的另一个优点是,操作系统可以在系统关闭时直接将缓冲区刷新到磁盘。 而且,操作系统可以锁定文件的映射部分,使其免受计算机上其他进程的影响。

分配很贵

直接缓冲区的问题之一是分配它们很昂贵。 无论缓冲区的大小如何,调用ByteBuffer.allocateDirect()都是一个相对较慢的操作。 因此,对于大型和长寿命的缓冲区使用直接缓冲区,或者创建一个大型缓冲区,按需分割部分,并在不再需要它们时将它们返回以重新使用,效率更高。 当切片的大小不总是相同时,可能会出现切片问题。 当分配和释放不同大小的对象时,初始的大字节缓冲区可能会变得碎片化。 与Java堆不同,直接字节缓冲区无法压缩,因为它不是垃圾收集器的目标。

监视缓冲池的使用

如果您对应用程序使用的直接或映射的字节缓冲区的数量感兴趣,则可以使用许多工具(包括VisualVM(带有BufferMonitor插件)和FusionReactor)轻松监视它们。 Java将根据需要增加缓冲池,因此“已使用的直接内存”涵盖了下图的“直接容量”这一事实,这意味着到目前为止分配的所有缓冲内存都在使用中。

请注意–您可以使用-XX:MaxDirectMemorySize=N标志来限制应用程序可以分配的直接字节缓冲区空间量。 尽管这是可能的,但是您将需要一个很好的理由。

翻译自: https://www.javacodegeeks.com/2018/03/understanding-java-buffer-pool.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值