DirectBuffer
在nio以前,是没有光明正大的做法的,有一个work around的办法是直接访问Unsafe类。如果你使用Eclipse,默认是不允许访问sun.misc下面的类的,你需要稍微修改一下,给Type Access Rules里面添加一条所有类都可以访问的规则:
在使用Unsafe类的时候:
Unsafe f = Unsafe.getUnsafe();
发现还是被拒绝了,抛出异常:
java.lang.SecurityException: Unsafe
正如Unsafe的类注释中写道:
Although the class and all methods are public, use of this class is limited because only trusted code can obtain instances of it.
于是,只能使用反射来做这件事;
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe us = (Unsafe) f.get(null);
long id = us.allocateMemory(1024 * 1024 * 1024);
其中,allocateMemory返回一个指针,并且其中的数据是未初始化的。如果要释放这部分内存的话,需要调用freeMemory或者reallocateMemory方法。Unsafe对象提供了一系列put/get方法,例如putByte,但是只能一个一个byte地put,我不知道这样会不会影响效率,为什么不提供一个putByteArray的方法呢?
示例:
import sun.misc.Unsafe; public class ObjectInHeap
{
private long address = 0; private Unsafe unsafe = GetUsafeInstance.getUnsafeInstance(); public ObjectInHeap()
{
address = unsafe.allocateMemory(2 * 1024 * 1024);
} // Exception in thread "main" java.lang.OutOfMemoryError
public static void main(String[] args)
{
while (true)
{
ObjectInHeap heap = new ObjectInHeap();
System.out.println("memory address=" + heap.address);
}
}
}
这段代码会抛出OutOfMemoryError。这是因为ObjectInHeap对象是在堆内存中分配的,当该对象被垃圾回收的时候,并不会释放堆外内存,因为使用Unsafe获取的堆外内存,必须由程序显示的释放,JVM不会帮助我们做这件事情。由此可见,使用Unsafe是有风险的,很容易导致内存泄露。
4、正确释放Unsafe分配的堆外内存
虽然第3种情况的ObjectInHeap存在内存泄露,但是这个类的设计是合理的,它很好的封装了直接内存,这个类的调用者感受不到直接内存的存在。那怎么解决ObjectInHeap中的内存泄露问题呢?可以覆写Object.finalize(),当堆中的对象即将被垃圾回收器释放的时候,会调用该对象的finalize。由于JVM只会帮助我们管理内存资源,不会帮助我们管理数据库连接,文件句柄等资源,所以我们需要在finalize自己释放资源。
import sun.misc.Unsafe; public class RevisedObjectInHeap
{
private long address = 0; private Unsafe unsafe = GetUsafeInstance.getUnsafeInstance(); // 让对象占用堆内存,触发[Full GC
private byte[] bytes = null; public RevisedObjectInHeap()
{
address = unsafe.allocateMemory(2 * 1024 * 1024);
bytes = new byte[1024 * 1024];
} @Override
protected void finalize() throws Throwable
{
super.finalize();
System.out.println("finalize." + bytes.length);
unsafe.freeMemory(address);
} public static void main(String[] args)
{
while (true)
{
RevisedObjectInHeap heap = new RevisedObjectInHeap();
System.out.println("memory address=" + heap.address);
}
} }
我们覆盖了finalize方法,手动释放分配的堆外内存。如果堆中的对象被回收,那么相应的也会释放占用的堆外内存。这里有一点需要注意下:
// 让对象占用堆内存,触发[Full GC
private byte[] bytes = null;
这行代码主要目的是为了触发堆内存的垃圾回收行为,顺带执行对象的finalize释放堆外内存。如果没有这行代码或者是分配的字节数组比较小,程序运行一段时间后还是会报OutOfMemoryError。这是因为每当创建1个RevisedObjectInHeap对象的时候,占用的堆内存很小(就几十个字节左右),但是却需要占用2M的堆外内存。这样堆内存还很充足(这种情况下不会执行堆内存的垃圾回收),但是堆外内存已经不足,所以就不会报OutOfMemoryError。
DirectBuffer的更多相关文章
- java NIO buffer --directBuffer (2)
HeapBuffer ----堆缓冲 :其实是在java 的内存模型中,java 虚拟机可以直接管控的 DirectBuffer ---直接缓冲 :使用的是native ,与操作系统挂钩,调用的 ...
- java NIO - DirectBuffer 和 HeapBuffer
问题 : DirectBuffer 属于堆外存,那应该还是属于用户内存,而不是内核内存? FileChannel 的read(ByteBuffer dst)函数,write(ByteBuffer sr ...
- Java NIO浅析
NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接 ...
- Java直接内存与堆内存
NIO的Buffer提供了一个可以不经过JVM内存直接访问系统物理内存的类——DirectBuffer. DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同,普通 ...
- [转]netty对http协议解析原理
本文主要介绍netty对http协议解析原理,着重讲解keep-alive,gzip,truncked等机制,详细描述了netty如何实现对http解析的高性能. 1 http协议 1.1 描述 标示 ...
- Java直接(堆外)内存使用详解
本篇主要讲解如何使用直接内存(堆外内存),并按照下面的步骤进行说明: 相关背景-->读写操作-->关键属性-->读写实践-->扩展-->参考说明 希望对想使用直接内存的朋 ...
- Java读取Level-1行情dbf文件极致优化(2)
最近架构一个项目,实现行情的接入和分发,需要达到极致的低时延特性,这对于证券系统是非常重要的.接入的行情源是可以配置,既可以是Level-1,也可以是Level-2或其他第三方的源.虽然Level-1 ...
- 二:基础概述netty
如果不了解netty的,可以百度下,netty社区现在也比较活跃. 现在所谓的大数据,flume,storm等底层都是netty. netty的性能模型: io模型---->异步非阻塞io ...
- Java NIO 基础
Java在JDK1.4中引入了 java.nio 类库,为Java进军后端Server和中间件开发打开了方便之门. 一般而言,这里的 nio 代表的是 New I/O,但是从实质上来说,我们可以将其理 ...
随机推荐
- JSON.parse()和JSON.stringify()的区别
1. parse用于从一个字符串中解析出json对象,如 var str = '{"name":"huangxiaojian","age": ...
- [双连通分量] POJ 3694 Network
Network Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 9434 Accepted: 3511 Descripti ...
- PR和VV的分类与区别
Adobe Premiere是一款常用的视频编辑软件,由Adobe公司推出.现在常用的有CS4.CS5.CS6.CC.CC 2014及CC 2015版本.是一款编辑画面质量比较好的软件,有较好的兼容性 ...
- Hadoop运行错误纪录
问题1:Cannot run program "/bin/ls": error=11, Resource temporarily unavailable 15/04/22 14:4 ...
- python mysql 更新和插入数据无效
注意,在删除和增加后必须执行conn.commit()才有效,否则操作无效.
- Volley框架的使用
所谓Volley,它是2013年Google I/O上发布的一款网络框架,基于Android平台,能使网络通信更快,更简单,更健全. 它的优点:(1)默认Android2.3及以上基于HttpURLC ...
- POJ 2155 2维线段树 || 2维BIT
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> ...
- SDK、MFC、QT界面生成的机制
1.SDK进行界面设计的机制 (1)设计窗口类 (2)注册窗口类 (3)创建窗口 (4)显示及更新窗口 (5)消息循环,操作系统接收到应用程序的窗口消息,将消息投递到队列中,通过GetMessage( ...
- JQuery源码解析(十)
默认回调对象设计 不传入任何参数,调用add的时候将函数add到内部的list中,调用fire的时候顺序触发list中的回调函数: function fn1(val) { console.log('f ...
- HDU 1254
http://acm.hdu.edu.cn/showproblem.php?pid=1254 暴搜,状态是四维的(箱子和人的坐标),向一个方向推箱子还要判断人能否走到推的位置,1A #include ...