java nio 堆外内存_java Nio堆外内存和零拷贝

allocateDirect会通过C/C++的native方法创建堆外内存,java虚拟机无法直接操作.

/**

* Allocates a new direct byte buffer.

*

*

The new buffer's position will be zero, its limit will be its

* capacity, its mark will be undefined, and each of its elements will be

* initialized to zero. Whether or not it has a

* {@link #hasArray backing array} is unspecified.

*

* @param capacity

* The new buffer's capacity, in bytes

*

* @return The new byte buffer

*

* @throws IllegalArgumentException

* If the capacity is a negative integer

*/

public static ByteBuffer allocateDirect(int capacity) {

return new DirectByteBuffer(capacity);

}

是通过address属性来访问堆外内存的

public abstract class Buffer {

/**

* The characteristics of Spliterators that traverse and split elements

* maintained in Buffers.

*/

static final int SPLITERATOR_CHARACTERISTICS =

Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;

// Invariants: mark <= position <= limit <= capacity

private int mark = -1;

private int position = 0;

private int limit;

private int capacity;

// Used only by direct buffers

// NOTE: hoisted here for speed in JNI GetDirectBufferAddress

long address;

hosted是升级的意思.

因为按道理来说address应该放到DirectByteBuffer当中,但是却放到了他的父类Buffer当中,所以这叫做升级.

是为了加快JNI方法调用.

address表示的是堆外内存的地址.

不直接在堆上面分配内存,而要在堆外分配内存,可以免去java堆和OS native堆之间的数据交互,实现零拷贝,zeroCopy.

为什么一定要把数据从java堆里面拷贝出来呢?为什么OS不直接使用堆里面的数据呢?因为java堆里面的数据,有可能出现GC,当出现GC的时候,数据的内存地址就发生了变化,如果OS在使用数据的时候发生GC的话,整个就乱套了.所以必须要拷贝一份到OS内核中.

JVM会保证在拷贝过程中不会发生GC

DirectByteBuffer被回收的时候,相应的堆外内存也会被回收,不会出现内存泄露的情况.

public class readAndWrite1 {

/**

* allocateDirect返回的是一个DirectByteBuffer

* 那么DirectByteBuffer相比于HeapByteBuffer有什么不同

* 1.HeapByteBuffer这个对象是存在堆上。而DirectByteBuffer,在使用堆内存的同时还会使用堆外内存,他这个对象在堆上,而buffer数组在堆外内存。

* 2.堆外内存:即调用native方法,使用C或C++编写的方法处理数据。(在堆外,但是我们java是在堆内存啊,要使用堆外内存怎么办)

* 3.在DirectByteBuffer中有个long类型的address指向堆外内存,那么凭借这个我们就可以连接两块内存。

* 那为啥要用到堆外内存?

* 1.普通的在堆上分配的内存,在操作系统进行读取时,需要先将堆内存复制一份到操作系统,这样速度就受限了。(这种复制情况也是受限于需要对IO设备进行交互,例如文件读取等)

* (疑问:为啥操作系统需要复制一份数据,不可以直接读取吗?可以,但是不能这样。主要原因是java有垃圾回收机制,操作系统可能就在读取数据时发生了垃圾回收

* 其中标记整理法会将内存压缩,这样不就打乱了数组顺序吗?所以操作系统复制一份进行操作.

* 因此DirectByteBuffer在堆外分配,就不需要操作系统拷贝了,也被称为0拷贝.

* )

* 2.如果使用堆外内存,操作系统直接读取,速度超快。

* 总结:DirectByteBuffer(直接缓冲区),直接本地IO操作,避免了java虚拟机复制一块中间缓冲区。

* * @param args

* @throws IOException

*/

public static void main(String[] args) throws IOException {

FileInputStream in=new FileInputStream("input.txt");

FileOutputStream out=new FileOutputStream("out.txt");

FileChannel fileInChannel=in.getChannel();

FileChannel fileOutChannel=out.getChannel();

ByteBuffer byteBuffer=ByteBuffer.allocateDirect(512);

while (true){

byteBuffer.clear();

int read=fileInChannel.read(byteBuffer);

System.out.println("read:"+read);

if ( -1 == read){

break;

}

byteBuffer.flip();

fileOutChannel.write(byteBuffer);

}

fileInChannel.close();

fileOutChannel.close();

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值