美文网首页JAVAAndroid开发Android知识
堆外内存的回收机制分析

堆外内存的回收机制分析

作者: 美团Java | 来源:发表于2017-07-01 18:29 被阅读4973次

占小狼
转载请注明原创出处,谢谢!

堆外内存

JVM启动时分配的内存,称为堆内存,与之相对的,在代码中还可以使用堆外内存,比如Netty,广泛使用了堆外内存,但是这部分的内存并不归JVM管理,GC算法并不会对它们进行回收,所以在使用堆外内存时,要格外小心,防止内存一直得不到释放,造成线上故障。

堆外内存的申请和释放

JDK的ByteBuffer类提供了一个接口allocateDirect(int capacity)进行堆外内存的申请,底层通过unsafe.allocateMemory(size)实现,接下去看看在JVM层面是如何实现的。

可以发现,最底层是通过malloc方法申请的,但是这块内存需要进行手动释放,JVM并不会进行回收,幸好Unsafe提供了另一个接口freeMemory可以对申请的堆外内存进行释放。

堆外内存的回收机制

如果每次申请堆外内存,都需要在代码中显示的释放,对于Java这门语言的设计来说,显然不够合理,既然JVM不会管理这些堆外内存,它们是如何回收的呢?

DirectByteBuffer

JDK中使用DirectByteBuffer对象来表示堆外内存,每个DirectByteBuffer对象在初始化时,都会创建一个对用的Cleaner对象,这个Cleaner对象会在合适的时候执行unsafe.freeMemory(address),从而回收这块堆外内存。

当初始化一块堆外内存时,对象的引用关系如下:

其中firstCleaner类的静态变量,Cleaner对象在初始化时会被添加到Clener链表中,和first形成引用关系,ReferenceQueue是用来保存需要回收的Cleaner对象。

如果该DirectByteBuffer对象在一次GC中被回收了

此时,只有Cleaner对象唯一保存了堆外内存的数据(开始地址、大小和容量),在下一次FGC时,把该Cleaner对象放入到ReferenceQueue中,并触发clean方法。

Cleaner对象的clean方法主要有两个作用:
1、把自身从Clener链表删除,从而在下次GC时能够被回收
2、释放堆外内存

public void run() {
    if (address == 0) {
        // Paranoia
        return;
    }
    unsafe.freeMemory(address);
    address = 0;
    Bits.unreserveMemory(size, capacity);
}

如果JVM一直没有执行FGC的话,无效的Cleaner对象就无法放入到ReferenceQueue中,从而堆外内存也一直得不到释放,内存岂不是会爆?

其实在初始化DirectByteBuffer对象时,如果当前堆外内存的条件很苛刻时,会主动调用System.gc()强制执行FGC。

不过很多线上环境的JVM参数有-XX:+DisableExplicitGC,导致了System.gc()等于一个空函数,根本不会触发FGC,这一点在使用Netty框架时需要注意是否会出问题。

相关文章

  • 垃圾回收 jvm 经典文章

    堆外内存的回收机制分析https://www.jianshu.com/p/35cf0f348275 看完这篇垃圾回...

  • 堆外内存的回收机制分析

    占小狼转载请注明原创出处,谢谢! 堆外内存 JVM启动时分配的内存,称为堆内存,与之相对的,在代码中还可以使用堆外...

  • Java非堆内存的回收

    jvm的垃圾回收机制大家应该已经很熟了,jvm主要是回收堆内存,而我我们在开发中会遇到在堆外分配内存的情况,那这部...

  • 深入分析堆外内存的回收机制

    JVM启动时分配的内存,称为堆内存,与之相对的,在代码中还可以使用堆外内存,比如Netty,广泛使用了堆外内存,但...

  • try catch finally

    java的垃圾回收机制不会回收任何的物理资源,垃圾回收机制只回收堆内存中对象所占用的内存 当程序执行try块,ca...

  • Java堆外内存的回收机制

    1 堆外内存 JVM启动时分配的内存,称为堆内存,与之相对的,在代码中还可以使用堆外内存,不如Netty,广泛使用...

  • Python基础入门 - 内存管理与多线程

    1. 内存管理机制 1.1 介绍 概要赋值语句内存分析垃圾回收机制内存管理机制 目标掌握赋值语句内存分析方法掌握i...

  • JVM内存回收机制简述

    关于JVM的内存主要关注点在几个方面: 一、内存回收机制的基础:分代收集算法 二、堆内存回收------如何判断对...

  • 简述GC

    垃圾回收机制;在堆内存的有没有被引用的对象的时候就会被被触发回收;除了jvm自动回收之外(内存不足自动回收),也可...

  • JVM之Java垃圾回收机制

    为大家推荐一篇写的通俗易懂的关于Java垃圾回收机制的文章理解Java垃圾回收机制 Java主要把内存分为堆内存和...

网友评论

  • 26ac803361a7:你好,当堆外内存条件很苛刻怎么理解
  • 232bcc01cd64:Some time after the GC detects that a cleaner's referent has become phantom-reachable, the reference-handler thread will run the cleaner.
    狼哥,请教你一个问题,为什么是Sometime,还有那个reference-handler thread 是在哪创建的?
  • tomas家的小拨浪鼓:恩,这里说因为FGC才能触发堆外内存的回收并不严谨?? 因为一般堆外内存一般用于生命周期较长的对象,这导致DirectByteBuffer在几次YGC后会被放入到老年代,从而来说,一般是需要通过FGC来触发堆外内存的回收。 👈个人理解,是这样吗?
  • 90bb5aacf3ff:直观明了 就喜欢狼哥这风格
    美团Java:@䒕愺 :heart:
  • 1431d58ab1db:堆外内存分配时,页对齐,为什么要多分配一个页内存大小
  • 4eadb3ef44df:只有在FullGC的时候才会回收堆外内存,那么对于一些对响应要求较高的系统怎么办?每次出发FullGC都会STW,这很矛盾啊。
    美团Java:@秋风画扇_1939 Netty对堆外内存的管理有自己的算法,更加高效,有兴趣可以看看
  • 开发者头条_程序员必装的App:感谢分享!已推荐到《开发者头条》:https://toutiao.io/posts/7h76y5 欢迎点赞支持!
    欢迎订阅《java进阶之路》https://toutiao.io/subjects/85249
  • 简书闪电侠:周末不陪陪妹纸嘛
    hongrm:@秋风画扇_1939 :joy:
    4eadb3ef44df:@占小狼 先把妹子挂起……
    美团Java:@the_flash 并发

本文标题:堆外内存的回收机制分析

本文链接:https://www.haomeiwen.com/subject/uddjcxtx.html