jvm中的直接内存,存在堆内存中其实就是DirectByteBuffer类,它本身很小,真的内存是在堆的外卖呢,这里是映射关系。
每次申请直接内存,都先看看是否已经达到了限定最大的直接内存大小(可以用 -XX:MaxDirectMemorySize设定),如果超出了,就会执行System.gc(),在GC的时候触发Stop-The-World ,因为是直接内存回收,时间会比较长,如果没有回收成功直接内存,并且还是超过直接内存的限额,就会抛出OOM
DirectByteBuffer熬过了几次young gc之后,会进入老年代。当老年代满了之后,会触发Full GC。
因为本身很小,很难占满老年代,因此基本不会触发Full GC,带来的后果是大量堆外内存一直占着不放,无法进行内存回收。还有最后一个办法,就是依靠申请额度超限时触发的system.gc(),但是它会中断进程100ms,如果在这100ms的之间,系统未完成GC,仍会抛出OOM。
直接 非直接内存的概念与NIO有非常大的关联;
在NIO之前,java.io 的方式是:
磁盘IO --> 直接内存[系统内核态] --> 非直接(堆)内存[用户态] --> 直接内存[系统内核态] --> 磁盘IO
而NIO中,对文件的读写不再跟堆内存关联
磁盘IO --> 系统直接内存 --> 磁盘IO
读写文件时可以直接申请堆外内存。