除了常说的虚拟机运行时数据区以外,还有一部分内存也被频繁使用,他不是运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,就是直接内存。
直接内存的分配不受Java堆大小的限制,但是他还是会收到服务器总内存的影响。
在JDK 1.4中引入的NIO中,引入了一种基于Channel和Buffer的I/O方式,他可以使用Native函数直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的应用进行操作。如下图所示:

代码测试如下:
import java.nio.ByteBuffer;
public class ByteBufferCompare {
public static void main(String[] args) {
allocateCompare();
System.out.println("——————————————————————————————————" );
operateCompare();
}
public static void operateCompare(){
//直接内存在直接的IO 操作上,在频繁的读写时 会有显著的性能提升
int time=10000000;
long startTime = System.currentTimeMillis();
ByteBuffer buffer = ByteBuffer.allocate(2*time);
read(time, buffer);
long endTime= System.currentTimeMillis();;
System.out.println("在进行"+time+"次读写操作时,非直接内存(堆)分配耗时:" + (endTime-startTime) +"ms" );
long sTime = System.currentTimeMillis();
ByteBuffer buffer2 = ByteBuffer.allocateDirect(2*time);
read(time, buffer2);
long eTime= System.currentTimeMillis();;
System.out.println("在进行"+time+"次读写操作时,直接内存分配耗时:" + (eTime-sTime) +"ms" );
}
private static void read(int time, ByteBuffer buffer) {
for (int i = 0; i <time; i++) {
buffer.putChar('a');
}
buffer.flip();//将缓存字节数组的指针设置为数组的开始序列即数组下标0。方便进行遍历(读取)
for (int i = 0; i < time; i++) {
buffer.getChar();
}
}
public static void allocateCompare(){
//直接内存分配比堆内存分配更慢
int time=10000000;
long startTime = System.currentTimeMillis();
for (int i = 0; i <time; i++) {
ByteBuffer buffer = ByteBuffer.allocate(2);
}
long endTime = System.currentTimeMillis();
System.out.println("在进行"+time+"次分配操作时,非直接内存(堆)分配耗时:" + (endTime-startTime) +"ms" );
long sTime = System.currentTimeMillis();
for (int i = 0; i <time; i++) {
ByteBuffer buffer = ByteBuffer.allocateDirect(2);
}
long eTime = System.currentTimeMillis();
System.out.println("在进行"+time+"次分配操作时,直接内存分配耗时:" + (eTime-sTime) +"ms" );
}
}
执行结果如下:

小结:
在分配内存时,堆内存分配的速度明显比直接内存分配的速度快,尤其是数据量增大之后;
而在频繁的IO操作时,按道理来说应该是直接内存更快,但是在这里答主的内存不够,再往上加就Java heap space,所以想要尝试的话可以自己修改time的值来测试。
网友评论