Java的非堆内存与元空间

一、堆与非堆

按照官方的说法:“Java 虚拟机具有一个堆(Heap),堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。

二、堆与非堆的监控

我们怎么查看Java进程占用的堆内存有多大,非堆内存有多大呢?

public class Test {
    public static void main(String[] args) {
        //申请100M的空间
        ByteBuffer buf = ByteBuffer.allocate(1024 * 1024* 100);
        //申请100M的空间
        ByteBuffer buf2 = ByteBuffer.allocateDirect(1024 * 1024* 100);
        // 获取元空间的初始容量和最大容量等参数
        MemoryUsage nonHeapMemoryUsage = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
        MemoryUsage heapMemoryUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
        System.out.println("NonHeapMemoryUsage Used: " + (nonHeapMemoryUsage.getUsed() / 1024 / 1024) + " MB");
        System.out.println("HeapMemoryUsage Used: " + (heapMemoryUsage.getUsed() / 1024 / 1024) + " MB");
    }
}

对应的输出为:

NonHeapMemoryUsage Used: 4 MB
HeapMemoryUsage Used: 109 MB

总结:通过 ManagementFactory.getMemoryMXBean()就能获得对应的MemoryUsage对象,然后就能获得到对应的占用内存

三、堆内存与非堆内存由哪些内存组成

我们继续深挖一下,堆内存是由哪些内存组成的呢?

1、堆内存

请看下图:

堆内存由两部分组成:一个是新生代,一个是老年代,在这个里面我们经常会听到young gc和full gc。

2、非堆内存

在Java8中,很多人会认为非堆内存就是Metaspace的大小,其实这是一个误解,非堆内存要比Metaspace大,见下图:

2.1、Metaspace

元空间(Metaspace)是Java 8之后引入的一种新的内存区域,用于替代旧版的永久代(Permanent Generation)。元空间的主要作用是存储类的元数据信息,包括类的结构信息、方法信息、字段信息、注解信息、常量池等。

2.2、CodeCache

CodeCache是一块独立于 java 堆之外的内存区域,存放 jit 编译的代码

通过JVM参数-XX:ReservedCodeCacheSize=256M设置Code Cache 的总容量上限。

2.3、Compressed Class Space

在JVM调优中,压缩类空间(Compressed Class space)是一种用来减少JVM内存占用的技术。它的作用是将类元数据信息(例如类名、访问修饰符等)进行压缩,从而减少类加载器所需的内存空间。当JVM堆内存小于32G时,JVM默认会启用CompressedOops(压缩指针)优化,这个优化让对象引用占用32bit,而不是64bit。另外,通过启用UseCompressedClassPointers这个选项,也是默认启用的,将能够把每个对象的类的指针压缩为32bit,当这个选项开启时,类元数据被从Metaspace转移到另一个区域:Compressed class space(压缩类空间)。

3、如何监控

for (java.lang.management.MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
            System.out.println(pool.getName() + "   " + (pool.getUsage().getUsed() / 1024 / 1024) + " MB");
        }

结果:

Code Cache   1 MB
Metaspace   3 MB
Compressed Class Space   0 MB
PS Eden Space   9 MB
PS Survivor Space   0 MB
PS Old Gen   100 MB