Appearance
1、直接内存是什么?
- 直接内存是一块由操作系统直接管理的内存,也叫对外内存,IO效率较高
- 可以使用Unsafe或ByteBuffer分配直接内存
- Unsafe
- 溢出时报:java.lang.OutOfMemoryError
- -XX:MaxDirectMemorySize不起作用
- ByteBuffer
- 溢出时报:java.lang.OutOfMemoryError:Direct buffer memory
- -XX:MaxDirectMemorySize起作用
- ByteBuffer底层也是Unsafe去分配内存
- Unsafe
- 可用-XX:MaxDirectMemorySize控制,默认是0,表示不限制
2、为什么要用直接内存?
- 性能优势
- 堆内存vs直接内存
3、使用场景
- 有很大的数据需要存储,生命周期很长
- 频繁的IO操作,如并发网络通信
4、分配直接内存
- Unsafe.allocatememory(size)
- ByteBuffer.allocateDirect(size)
java
package com.zhz.jvm.tuning;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class DirectMemoryTest1 {
private static final int MB_1 = 1024 * 1024;
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
//通过反射获取Unsafe类并通过其分配直接内存
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
// 分配1M内存,并返回这块内存的起始地址
long address = unsafe.allocateMemory(MB_1);
// 向内存地址中设置对象
unsafe.putByte(address, (byte) 1);
// 从内存中获取对象
byte aByte = unsafe.getByte(address);
System.out.println(aByte);
// 释放内存
unsafe.freeMemory(address);
}
}
java
package com.zhz.jvm.tuning;
import java.nio.ByteBuffer;
public class DirectMemoryTest2 {
private static final int ONE_MB = 1024 * 1024;
/**
* ByteBuffer参考文档:
* https://blog.csdn.net/z69183787/article/details/77102198/
*
* @param args args
*/
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocateDirect(ONE_MB);
// 相对写,向position的位置写入一个byte,并将postion+1,为下次读写作准备
buffer.put("abcde".getBytes());
buffer.put("fghij".getBytes());
// 转换为读取模式
buffer.flip();
// 相对读,从position位置读取一个byte,并将position+1,为下次读写作准备
// 读取第1个字节(a)
System.out.println((char) buffer.get());
// 读取第2个字节
System.out.println((char) buffer.get());
// 绝对读,读取byteBuffer底层的bytes中下标为index的byte,不改变position
// 读取第3个字节
System.out.println((char) buffer.get(2));
}
}
java
package com.zhz.jvm.tuning;//package com.imooc.jvminaction;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
// 1. Unsafe导致直接内存溢出报错没有小尾巴
// 2. -XX:MaxDirectMemorySize=100m对Unsafe不起作用
public class DirectMemoryTest3 {
private static final int GB_1 = 1024 * 1024 * 1024;
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
//通过反射获取Unsafe类并通过其分配直接内存
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
int i = 0;
while (true) {
unsafe.allocateMemory(GB_1);
System.out.println(++i);
}
}
}
java
package com.zhz.jvm.tuning;
import java.nio.ByteBuffer;
// 1. ByteBuffer直接内存溢出报错是java.lang.OutOfMemoryError: Direct buffer memory
// 2. -XX:MaxDirectMemorySize对ByteBuffer有效
public class DirectMemoryTest4 {
private static final int GB_1 = 1024 * 1024 * 1024;
/**
* ByteBuffer参考文档:
* https://blog.csdn.net/z69183787/article/details/77102198/
*
* @param args args
*/
public static void main(String[] args) {
int i= 0;
while (true) {
ByteBuffer buffer = ByteBuffer.allocateDirect(GB_1);
System.out.println(++i);
}
}
}
5、直接内存经验之说
- 堆Dump文件看不出问题或者比较小,可考虑直接内存溢出问题
- 配置内存时,应给直接内存预留足够的空间