JVM中的堆外内存(off-heap memory)与堆内内存(on-heap memory)

1. 堆内内存(on-heap memory)

1.1 什么是堆内内存

Java 虚拟机在执行Java程序的过程当中会把它在主存中管理的内存部分划分红多个区域,每一个区域存放不一样类型的数据。下图所示为java虚拟机运行的时候,主要的内存分区:java

这里写图片描述

在这些分区中,占用内存空间最大的一部分叫作“堆(heap)”,也就是咱们所说的堆内内存(on-heap memory)。java虚拟机中的“堆”主要是存放全部对象的实例。这一块区域在java虚拟机启动的时候被建立,被全部的线程所共享,同时也是垃圾收集器的主要工做区域,所以这一部分区域除了被叫作“堆内内存”之外,也被叫作“GC堆”(Garbage Collected Heap)。web

1.2 堆内内存的垃圾回收

堆内内存是java垃圾收集器的主要工做区域,为了提升垃圾回收的效率,在堆内内存的内部又划分出了新生代、老年代和永久代。在新生代内存中又按照8:1:1的比例(java虚拟机默认分配比例为8:1:1,这个比例也能够自定义)划分出了Eden, Survivor1, Survivor2三个区域。算法

在执行垃圾回收算法的时候,不一样的回收算法会对内存区域形成不同的影响。可是大部分的回收算法会形成堆内内存空间在物理上的不连续性。下面以最基本的垃圾回收算法“标记 - 清除算法”为例:数据结构

这里写图片描述

能够看到,内存区域在通过垃圾回收以后,产生大量不连续的内存空间。所以,java虚拟机中的堆内内存区域,只是逻辑上的连续,并不能保证物理上的连续性。 因此,操做系统并不能直接获得堆内内存区域所存储的数据在主存中的正确地址。在一些特定的时间点,Java虚拟机会进行一次完全的垃圾回收(full gc)。完全回收时,垃圾收集器会对全部分配的堆内内存进行完整的扫描,在扫描期间,绝大部分正在运行的java线程都会被暂时中止。这意味着:这样一次垃圾收集对Java应用形成的影响,跟堆内内存所存储的数据的多少是成正比的,过大的堆内内存会影响Java应用的性能。svg

2. 堆外内存(off-heap memory)

2.1 堆外内存的产生

为了解决堆内内存过大带来的长时间的GC停顿的问题,以及操做系统对堆内内存不可知的问题,java虚拟机开辟出了堆外内存(off-heap memory)。堆外内存意味着把一些对象的实例分配在Java虚拟机堆内内存之外的内存区域,这些内存直接受操做系统(而不是虚拟机)管理。这样作的结果就是能保持一个较小的堆,以减小垃圾收集对应用的影响。同时由于这部分区域直接受操做系统的管理,别的进程和设备(例如GPU)能够直接经过操做系统对其进行访问,减小了从虚拟机中复制内存数据的过程。性能

2.2 堆外内存的分配

java 在NIO 包中提供了ByteBuffer类,对堆外内存进行访问。下图为NIO包中ByteBuffer的层次继承关系spa

这里写图片描述

使用下面的方式,能够直接开辟指定大小的对外内存:操作系统

import sun.nio.ch.DirectBuffer;

import java.nio.ByteBuffer;

public class TestDirectByteBuffer {
    public static void main(String[] args) throws Exception {
        while (true) {
            ByteBuffer buffer = ByteBuffer.allocateDirect(10 * 1024 * 1024);
        }
    }
}

这样咱们就开辟出了一块大小为10M的堆外内存。线程

3. 堆外内存的优缺点以及与堆内内存联系

3.1堆外内存的优缺点:

优势 :code

  1. 能够很方便的自主开辟很大的内存空间,对大内存的伸缩性很好
  2. 减小垃圾回收带来的系统停顿时间
  3. 直接受操做系统控制,能够直接被其余进程和设备访问,减小了本来从虚拟机复制的过程
  4. 特别适合那些分配次数少,读写操做很频繁的场景

缺点 :

  1. 容易出现内存泄漏,而且很难排查
  2. 堆外内存的数据结构不直观,当存储结构复杂的对象时,会浪费大量的时间对其进行串行化。

3.2 堆内内存与堆外内存的联系:

虽然堆外内存自己不受垃圾回收算法的管辖,可是由于其是由ByteBuffer所创造出来的,所以这个buffer自身做为一个实例化的对象,其自身的信息(例如堆外内存在主存中的起始地址等信息)必须存储在堆内内存中,具体状况以下图所示。

这里写图片描述

当在堆内内存中存放的buffer对象实例被垃圾回收算法回收掉的时候,这个buffer对应的堆外内存区域同时也就被释放掉了。