06、JVM实战:内存区域:直接内存

06–内存区域–直接内存


1、结构图

*

2、直接内存(堆外内存)

1、 直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中农定义的内存区域;
2、 在JDK1.4中新加入了NIO(NewInput/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用native函数库直接分配堆外内存(直接内存),然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据;
3、 本机直接内存的分配不会受到Java堆大小的限制,受到本机总内存大小限制;
4、 配置虚拟机参数时,不要忽略直接内存,防止出现OutOfMemoryError异常;

2.1、 直接内存(堆外内存)与堆内存比较

1、 直接内存申请空间耗费更高的性能,当频繁申请到一定量时尤为明显;
2、 直接内存IO读写的性能要优于普通的堆内存,在多次读写操作的情况下差异明显;

2.2、 直接内存使用场景

1、 有很大的数据需要存储,它的生命周期很长;
2、 适合频繁的IO操作,例如网络并发场景;

2.3、 内存溢出案例

package com.fei.zhou.day1;

import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class DirectMemoryOOMTest {

	/**
	 * VM Args:-Xms20m -Xmx20m -XX:MaxDirectMemorySize=10m
	 * @param args
	 */
	public static void main(String[] args) {
	    int i=0;
	    try {
	        Field field = Unsafe.class.getDeclaredFields()[0];
	        field.setAccessible(true);
	        Unsafe unsafe = (Unsafe) field.get(null);
	        while(true){
	        	//申请内存1M
	            unsafe.allocateMemory(1024*1024);
	            i++;
	        }
	    } catch (Exception e) {
	        e.printStackTrace();
	    }finally {
	        System.out.println("分配次数:"+i);
	    }
	}
}

结果:
分配次数:9639
Exception in thread "main" java.lang.OutOfMemoryError
	at sun.misc.Unsafe.allocateMemory(Native Method)
	at com.fei.zhou.day1.DirectMemoryOOMTest.main(DirectMemoryOOMTest.java:21)