Java NIO笔记之Buffer
来源:互联网 发布:中国经济数据网 编辑:程序博客网 时间:2024/04/30 15:33
一个Buffer对象是固定数量的大小的数据容器,作用是一个存储器或者分段运输区。
缓冲区的工作与通道紧密联系。通道是I/O传输发生时通过的入口,而缓冲区是这些数据传输的来源或目标。对于离开缓冲区的传输,您想传递出去的数据被置于一个缓冲区,被传送到通道。对于传回缓冲区的传输,一个通道将数据放置在您所提供的缓冲区中。这种在协同对象(通常是您所写的对象以及一到多个Channel对象)之间进行的缓冲区数据传递是高效数据处理的关键。
Buffer的数据结构
public abstract class Buffer { // Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity; //... }
对缓冲区的读写操作首先要知道缓冲区的下限、上限和当前位置。下面这些变量的值对Buffer类中的某些操作有着至关重要的作用:
1.limit:所有对Buffer读写操作都会以limit变量的值作为上限。
2.position:代表对缓冲区进行读写时,当前游标的位置。
3.capacity:代表缓冲区的最大容量(一般新建一个缓冲区的时候,limit的值和capacity的值默认是相等的)。
部分方法:
//清空缓冲区的方法public final Buffer clear() { position = 0;//重置位置 limit = capacity;//重置limit mark = -1;//取消标记 return this; }
//在读取buffer之前调用public final Buffer flip() { limit = position;//当前位置设置为limit position = 0;//设置开始位置 mark = -1;//取消标记 return this; }
public final Buffer rewind() { position = 0; mark = -1; return this; }
Buffer子类的结构
下面主要是NIO出现内存泄露的情况,内容来自
http://stevex.blog.51cto.com/4300375/1582209
写NIO程序经常使用ByteBuffer来读取或者写入数据,那么使用ByteBuffer.allocate(capability)还是使用ByteBuffer.allocteDirect(capability)来分配缓存了?第一种方式是分配JVM堆内存,属于GC管辖范围,由于需要拷贝所以速度相对较慢;第二种方式是分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝所以速度相对较快。
我们肯定想选择比较快的,但问题是直接内存不属于GC管辖范围,需要弄清楚这部分内存如何管理,否则造成内存泄露就麻烦了。本地内存在JAVA中有一个对应的包装类DirectByteBuffer,该类属于Java类,适当的时候会被GC回收,当它被回收前会调用本地方法把直接内存给释放了,所以本地内存可以随DirectByteBuffer对象被回收而自动回收,貌似没有问题;但如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象们就不会被回收,这时候堆内存充足,但本地内存可能已经使用光了,再次尝试分配本地内存就会出现OutOfMemoryError,那程序就直接崩溃了。
有没有解决方案?自动释放不靠谱,我们是否可以手动释放本地内存,把握主动权?果然DirectByteBuffer持有一个Cleaner对象,该对象有一个clean()方法可用于释放本地内存,所以需要的时候我们可以调用这个方法手动释放本地内存。
以下代码与测试场景帮助理解与证实以上描述。
代码1:
package com.stevex.app.nio;import java.nio.ByteBuffer;import java.util.concurrent.TimeUnit;public class DirectByteBufferTest { public static void main(String[] args) throws InterruptedException{ //分配128MB直接内存 ByteBuffer bb = ByteBuffer.allocateDirect(1024*1024*128); TimeUnit.SECONDS.sleep(10); System.out.println("ok"); }}
测试用例1:设置JVM参数-Xmx100m,运行异常,因为如果没设置
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory at java.nio.Bits.reserveMemory(Bits.java:658) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306) at com.stevex.app.nio.DirectByteBufferTest.main(DirectByteBufferTest.java:8)
测试用例2:
设置JVM参数-Xmx256m,运行正常,因为128M小于256M,属于范围内分配。
测试用例3:
设置JVM参数-Xmx256m -XX:MaxDirectMemorySize=100M,运行异常,分配的直接内存128M超过限定的100M。
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory at java.nio.Bits.reserveMemory(Bits.java:658) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306) at com.stevex.app.nio.DirectByteBufferTest.main(DirectByteBufferTest.java:8)
代码2:
package com.stevex.app.nio;import java.nio.ByteBuffer;import java.util.concurrent.TimeUnit;import sun.nio.ch.DirectBuffer;public class DirectByteBufferTest { public static void main(String[] args) throws InterruptedException{ //分配512MB直接缓存 ByteBuffer bb = ByteBuffer.allocateDirect(1024*1024*512); TimeUnit.SECONDS.sleep(10); //清除直接缓存 ((DirectBuffer)bb).cleaner().clean(); TimeUnit.SECONDS.sleep(10); System.out.println("ok"); }}
测试用例4:设置JVM参数-Xmx768m,运行程序观察内存使用变化,会发现clean()后内存马上下降,说明使用clean()方法能有效及时回收直接缓存。
- Java NIO笔记之Buffer
- Java-NIO-Buffer-笔记
- Java NIO笔记(二):NIO Buffer(缓冲区)之基础
- Java NIO笔记(三):NIO Buffer(缓冲区)之进阶
- java nio之Buffer
- Java NIO 之 buffer
- Java NIO 之Buffer
- java nio之Buffer
- java NIO之buffer
- Java NIO 之 Buffer
- java nio之Buffer(一)
- 《JAVA NIO》之Buffer类图
- Java nio 之 buffer order
- Java之IO、NIO、Buffer
- NIO学习笔记之缓冲区Buffer
- 《Java源码分析》:Java NIO 之 Buffer
- 《Java源码分析》:Java NIO 之 Buffer
- java nio编程学习笔记(3)--buffer
- 算法竞赛入门经典 第二版 习题5-11 更新字典 Updating a Dictionary uva12504
- java中的值传递和引用传递
- Linux中关于init.d分析
- poj 2104 K-th Number (分桶法和平方分割)
- 什么是机器学习:一次权威定义之旅
- Java NIO笔记之Buffer
- 多线程2--毕向东基础视频教程学习笔记
- dpdk内存管理之内存初始化(内存收集)
- kernel32.dll函数介绍
- 动态内存分配:如何将两个字符串连接成单个字符串
- POJ3461:Oulipo(MP,KMP裸题)
- elasticsearch中doc_count为0,脚本失效?
- Ubuntu16.04下安装QT5.8
- Logistic Regression 逻辑回归算法