缓冲区溢出_了解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

缓冲区溢出

关于`FileSystemWatcher`消息池溢出的问题,通常情况下,FileSystemWatcher会持续监视文件系统的变更以触发应用程序的更新。如果文件系统活动频繁导致大量事件涌入,可能会超出默认的消息队列容量,从而引发溢出。 要解决这个问题,可以考虑以下策略[^1]: 1. **增大缓冲区大小**:可以通过调整Java的System.setProperty设置,如`sun.nio.fs.WindowsWatchService.MAX_BUFFER`, 来增加接收文件变更通知的缓冲区大小,但这可能不是长久之计,因为它依赖于操作系统限制。 ```java System.setProperty("sun.nio.fs.WindowsWatchService.MAX_BUFFER", "1024"); // 示例,具体数值需根据实际情况调整 ``` 2. **优化监听范围**:仅关注真正需要监视的重要目录,避免不必要的监视,减少事件数量。 3. **批量处理**:当接收到大量事件时,不要立即处理所有事件,而是分批处理,比如设定一个定时器,每次处理一定数量的事件,而不是一次性处理。 4. **降低事件频率**:如果是应用自身的行为导致的频繁更改,尝试修改应用程序的设计,使得更改更为稳定。 5. **使用异步机制**:如果可能,考虑使用异步IO或者回调模式,这样可以避免阻塞主线程并降低消息队列的压力。 6. **性能监控与调优**:定期检查和分析应用的内存使用情况,找出可能导致消息池溢出的具体瓶颈。 请注意,实际解决方案取决于特定的应用场景和配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值