Java堆外内存

Java中不需要手动的申请和释放内存,JVM会自动进行垃圾回收;而使用的内存是由JVM控制的。那么,什么时机会进行垃圾回收,如何避免过度频繁的垃圾回收?如果JVM给的内存不够用,怎么办?此时可以利用堆外内存,不仅可以随意操控内存,还能提高网络交互的速度。

背景

JVM内存的分配

新生代:一般来说新创建的对象都分配在这里。
年老代:经过几次垃圾回收,新生代的对象就会放在年老代里面。年老代中的对象保存的时间更久。
永久代:这里面存放的是class相关的信息,一般是不会进行垃圾回收的。

JVM垃圾回收

由于JVM会替我们执行垃圾回收,因此开发者根本不需要关心对象的释放。但是如果不了解其中的原委,很容易内存泄漏,只能两眼望天了。垃圾回收,大致可以分为下面几种:

  • Minor GC:当新创建对象,内存空间不够的时候,就会执行这个垃圾回收。由于执行最频繁,因此一般采用复制回收机制。
  • Major GC:清理年老代的内存,这里一般采用的是标记清除+标记整理机制。
  • Full GC:有的说与Major GC差不多,有的说相当于执行minor+major回收,那么我们暂且可以认为Full GC就是全面的垃圾回收吧。

堆外内存优缺点

堆外内存,其实就是不受JVM控制的内存。相比于堆内内存有几个优势:

  1. 减少了垃圾回收的工作,因为垃圾回收会暂停其他的工作(可能使用多线程或者时间片的方式,根本感觉不到)
  2. 加快了复制的速度。因为堆内在flush到远程时,会先复制到直接内存(非堆内存),然后在发送;而堆外内存相当于省略掉了这个工作;

堆外内存的缺点有:

  1. 堆外内存难以控制,如果内存泄漏,那么很难排查;
  2. 堆外内存相对来说,不适合存储很复杂的对象。一般简单的对象或者扁平化的比较适合;

堆外内存可以通过java.nio的ByteBuffer来创建,调用allocateDirect方法申请即可。此外,默认的情况下堆外内存是有一定的限制的(64M),可以通过设置-XX:MaxDirectMemorySize=10M控制堆外内存的大小。

堆外内存的垃圾回收