创建堆缓冲区与直接缓冲区
allocateDirect(int capacity): 分配新的直接字节缓冲区.新的缓冲区的位置将为0,其界限为其容量,其标记是不确定的.无论它是否具有底层实现数组,其标记都是不确定的.
allocate(int capacity): 分配一个新的非直接字节缓冲区.新缓冲区的位置为0,其界限为其容量,其标记是不确定的.它将具有一个底层实现数组,且其数组偏移量将为0.
如果字节缓冲区为直接字节缓冲区,则JVM会尽量在直接字节缓冲区上执行本机I/O操作,也就是直接对内核空间进行访问,以提高运行效率.提高运行效率的原理就是在每次调用基于操作系统地I/O操作之前或之后,JVM都会尽量避免将缓冲区的内容复制到中间缓冲区中,或者从中间缓冲区中复制内容,这样就节省了一个步骤.
通过allocateDirect()返回的缓冲区进行内存的分配和释放所需的时间成本通常高于非直接缓冲区.直接缓冲区操作的数据不在JVM堆中,而是在内核空间中,根据这个结构可以分析出,直接缓冲区善于保存那些易受操作系统本机I/O操作影响的大量、长时间保存到的数据。
使用allocateDirect()方法创建出来的缓冲区类型为DirectByteBuffer,使用allocate()方法创建出来的缓冲区类型为HeapByteBuffer.
使用allocateDirect()方法创建ByteBuffer缓冲区时,capacity指的是字节的个数,而创建IntBuffer缓冲区时,capacity指的是int值得数目,如果要转换成字节,则capacity要乘以4,来算出占用的总字节数。
直接缓冲区释放内存的方法
- 手动释放空间
package me.qianlv;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
/**
* @author xiaoshu
* 直接缓冲区释放内存方法
* 1. 手动释放
* 2. 交给JVM处理
* <p>
* 此程序运行的效果就是1秒钟之后立即回收内存
* 也就是回收"直接缓冲区"所占用的内存
*/
public class Test9 {
public static void main(String[] args) throws InterruptedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
System.out.println("A");
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(Integer.MAX_VALUE);
System.out.println("B");
byte[] byteArray = new byte[]{1};
System.out.println(Integer.MAX_VALUE);
for (int i = 0; i < Integer.MAX_VALUE; i++) {
byteBuffer.put(byteArray);
}
System.out.println("put end.");
TimeUnit.SECONDS.sleep(1);
Method cleanerMethod = byteBuffer.getClass().getMethod("cleaner");
cleanerMethod.setAccessible(true);
Object returnValue = cleanerMethod.invoke(byteBuffer);
Method cleanMethod = returnValue.getClass().getMethod("clean");
cleanMethod.setAccessible(true);
cleanMethod.invoke(returnValue);
}
}
复制代码
- 交给JVM进行处理
package me.qianlv;
import java.nio.ByteBuffer;
/**
* @author xiaoshu
* 直接缓冲区释放内存方法
* 1. 手动释放
* 2. 交给JVM处理
* <p>
* 此程序多次运行后,一直在耗费内存
* 进程结束后,也不会马上回收内存
* 而是会在某个时机触发GC垃圾回收器进行内存回收
*/
public class Test10 {
public static void main(String[] args) {
System.out.println("A");
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(Integer.MAX_VALUE);
System.out.println("B");
byte[] byteArray = new byte[]{1};
System.out.println(Integer.MAX_VALUE);
for (int i = 0; i < Integer.MAX_VALUE; i++) {
byteBuffer.put(byteArray);
}
System.out.println("put end.");
}
}
复制代码
此*.java类可以运行多次,产生多个进程,然后再查看内存使用情况会更加直观.
参考:
- 《NIO与Socket编程技术指南》