为什么要使用堆外内存?一般来说JVM内存有限且远小于物理内存,使用堆外内存可以直接利用物理内存。此外,堆内内存是可以用JVM工具直接dump出来的,而堆外内存的数据不能直接dump出来。
使用ByteBuffer开辟对外内存
在java中可以使用nio下的ByteBuffer简单的开辟对外内存。
根据堆外内存的特性,比如我们想把密码保存在内存,同时还不想密码被JVM工具dump出来,那我们可以实现代码:
public class PasswordStore {
private static final ByteBuffer PASSWORD_BUFFER = ByteBuffer.allocateDirect(1024);
public static synchronized byte[] getPassword() {
PASSWORD_BUFFER.flip();
int size = PASSWORD_BUFFER.limit();
if (size == 0) {
return null;
}
byte[] password = new byte[size];
PASSWORD_BUFFER.get(password);
return password;
}
public static synchronized void setPassword(char[] password) {
PASSWORD_BUFFER.clear();
for (char c : password) {
PASSWORD_BUFFER.put((byte) c);
}
}
}
并发安全的坑
注意上面的代码我加上了synchronized,是因为在并发时可能出现安全问题,比如两个线程出现如下交替执行时:
PASSWORD_BUFFER.flip(); // Thread 1
int size = PASSWORD_BUFFER.limit(); // Thread 1
PASSWORD_BUFFER.flip(); // Thread 2
// Thread 1
byte[] password = new byte[size];
PASSWORD_BUFFER.get(password); // java.nio.BufferUnderflowException
当线程2的flip方法插入在线程1的limit和get方法之间时,线程1在get时就会抛出异常BufferUnderflowException。