JAVA堆外内存

    JVM可使用的内存分外2种:堆内存和堆外内存.java

    堆内存彻底由JVM负责分配和释放,若是程序没有缺陷代码致使内存泄露,那么就不会遇到java.lang.OutOfMemoryError这个错误。函数

    使用堆外内存,就是为了能直接分配和释放内存,提升效率。JDK5.0以后,代码中能直接操做本地内存的方式有2种:使用未公开的Unsafe和NIO包下ByteBuffer。性能

    关于Unsafe对象的简介和获取方式,能够参考:http://blog.csdn.net/aitangyong/article/details/38276681测试

    使用ByteBuffer分配本地内存则很是简单,直接ByteBuffer.allocateDirect(10 * 1024 * 1024)便可。spa

    C语言的内存分配和释放函数malloc/free,必需要一一对应,不然就会出现内存泄露或者是野指针的非法访问。java中咱们须要手动释放获取的堆外内存吗?.net

    咱们一块儿来看看NIO中提供的ByteBuffer线程

      咱们将最大堆外内存设置成40M,运行这段代码会发现:程序能够一直运行下去,不会报OutOfMemoryError。若是使用了-verbose:gc -XX:+PrintGCDetails,会发现程序频繁的进行垃圾回收活动。那么DirectByteBuffer到底是如何释放堆外内存的?设计

    咱们修改下JVM的启动参数,从新运行以前的代码:3d

      与以前的JVM启动参数相比,增长了-XX:+DisableExplicitGC,这个参数做用是禁止代码中显示调用GC。代码如何显示调用GC呢,经过System.gc()函数调用。若是加上了这个JVM启动参数,那么代码中调用System.gc()没有任何效果,至关因而没有这行代码同样。指针

      显然堆内存(包括新生代和老年代)内存很充足,可是堆外内存溢出了。也就是说NIO直接内存的回收,须要依赖于System.gc()。若是咱们的应用中使用了java nio中的direct memory,那么使用-XX:+DisableExplicitGC必定要当心,存在潜在的内存泄露风险

     咱们知道java代码没法强制JVM什么时候进行垃圾回收,也就是说垃圾回收这个动做的触发,彻底由JVM本身控制,它会挑选合适的时机回收堆内存中的无用java对象。代码中显示调用System.gc(),只是建议JVM进行垃圾回收,可是到底会不会执行垃圾回收是不肯定的,可能会进行垃圾回收,也可能不会。何时才是合适的时机呢?通常来讲是,系统比较空闲的时候(好比JVM中活动的线程不多的时候),还有就是内存不足,不得不进行垃圾回收。咱们例子中的根本矛盾在于:堆内存由JVM本身管理,堆外内存必需要由咱们本身释放;堆内存的消耗速度远远小于堆外内存的消耗,但要命的是必须先释放堆内存中的对象,才能释放堆外内存,可是咱们又不能强制JVM释放堆内存。

Direct Memory的回收机制:Direct Memory是受GC控制的,例如ByteBuffer bb = ByteBuffer.allocateDirect(1024),这段代码的执行会在堆外占用1k的内存,Java堆内只会占用一个对象的指针引用的大小,堆外的这1k的空间只有当bb对象被回收时,才会被回收,这里会发现一个明显的不对称现象,就是堆外可能占用了不少,而堆内没占用多少,致使还没触发GC,那就很容易出现Direct Memory形成物理内存耗光。

Direct ByteBuffer分配出去的内存其实也是由GC负责回收的,而不像Unsafe是彻底自行管理的,Hotspot在GC时会扫描Direct ByteBuffer对象是否有引用,如没有则同时也会回收其占用的堆外内存。

参考:http://blog.csdn.net/aitangyong/article/details/39403031

          http://blog.csdn.net/aitangyong/article/category/2159887

          http://blog.csdn.net/aitangyong/article/details/39323125

          http://hellojava.info/?p=56

          http://hellojava.info/?tag=maxdirectmemorysize

          https://yq.aliyun.com/articles/2948

       使用堆外内存与对象池都能减小GC的暂停时间,这是它们惟一的共同点。生命周期短的可变对象,建立开销大,或者生命周期虽长但存在冗余的可变对象都比较适合使用对象池。生命周期适中,或者复杂的对象则比较适合由GC来进行处理。然而,中长生命周期的可变对象就比较棘手了,堆外内存则正是它们的菜。

堆外内存的好处是:

(1)能够扩展至更大的内存空间。好比超过1TB甚至比主存还大的空间;

(2)理论上能减小GC暂停时间;

(3)能够在进程间共享,减小JVM间的对象复制,使得JVM的分割部署更容易实现;

(4)它的持久化存储能够支持快速重启,同时还可以在测试环境中重现生产数据

站在系统设计的角度来看,使用堆外内存能够为你的设计提供更多可能。最重要的提高并不在于性能,而是决定性的

堆外内存说明请参见:http://ju.outofmemory.cn/entry/200574

                                    http://blog.csdn.net/aitangyong/article/category/2159887

相关文章
相关标签/搜索