JAVA堆内内存、堆外内存

定义

堆内存

完全由JVM负责分配和释放,如果代码有程序缺陷,可能是触发OOM

堆外内存

为了能直接分配和释放内存,提高效率。使用方式:使用未公开的Unsafe和NIO下的ByteBuffer

堆外内存的回收机制

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

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

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

NIO直接内存的回收,需要依赖于System.gc()。如果我们的应用中使用了java nio中的directmemory,那么使用-XX:+DisableExplicitGC一定要小心,存在潜在的内存泄露风险

堆内存由JVM自己管理,堆外内存必须要由我们自己释放;堆内存的消耗速度远远小于堆外内存的消耗,但要命的是必须先释放堆内存中的对象,才能释放堆外内存,但是我们又不能强制JVM释放堆内存。

堆外内存的好处

可以扩展至更大的内存空间。比如超过1TB甚至比主存还大的空间;

理论上能减少GC暂停时间;

可以在进程间共享,减少JVM间的对象复制,使得JVM的分割部署更容易实现;

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

猜你喜欢

转载自blog.csdn.net/a_ust/article/details/81056985
今日推荐