您的位置:

深入探究Java中的Nonheap

一、Nonheap介绍

Java虚拟机将内存划分为两个区域:heap和nonheap。

Heap区用于存储Java对象和JVM需要管理的数据。

Nonheap区用于存储JVM本身和Java类相关的信息。

除了Static数据和代码区,其他的Java代码都在Heap中运行。

而非Java数据的JVM或者Java类定义等信息是存储在Nonheap中的。

二、Nonheap的组成

Java中的Nonheap主要由Java虚拟机自己管理。

主要包含以下几个主要的元素:

1. Code Cache

Code Cache存放被JIT编译后的本地代码(native code)。

2. PermGen Space

PermGen Space存储Java类信息(例如类名称、访问修饰符等),以及方法和字段的元数据信息。

3. Metaspace

Java SE 8中,PermGen space被Metaspace替换,因为PermGen space在过多使用时会导致内存问题。所以,Metaspace用来存放类元信息。

4. Stack

Stack中存储着线程的运行状态,包括方法调用堆栈、局部变量信息和操作数栈。

5. Direct Buffers

Direct Buffers是non-heap的一部分。

6. JNI

Java Native Interface,是Java中调用非Java的C或其他本地库的接口。

三、代码示例

class NonHeapDemo{
    public static void main(String[] args) {
        //查找NonHeap区Header容量 
        long nonheapHeaderSize = sun.misc.VM.maxDirectMemory() - sun.misc.VM.currentDirectMemory();
        System.out.println("NonHeap Header Size: " + nonheapHeaderSize);

        //获取Code Cache大小
        long codeCacheSize = ((com.sun.management.HotSpotDiagnosticMXBean) ManagementFactory.getDiagnosticMXBean()).getLargestCompilationLevel();
        System.out.println("Code Cache Size: " + codeCacheSize);

        //获取PermGen Space或者Metaspace的大小
        long metaspaceSize = ((com.sun.management.GarbageCollectorMXBean) ManagementFactory.getGarbageCollectorMXBeans().get(0)).getMemoryPoolNames().stream()
                .filter(pool -> pool.contains("Metaspace"))
                .map(ManagementFactory::getMemoryPoolMXBean)
                .mapToLong(MemoryPoolMXBean::getUsage).mapToLong(Usage::getMax).sum();
        System.out.println("PermGen Space/Metaspace Size: " + metaspaceSize);

        //获取Direct Buffers大小
        long directBufferSize = ((com.sun.management.BufferPoolMXBean) ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class).get(0)).getTotalCapacity();
        System.out.println("Direct Buffer Size: " + directBufferSize);

        //获取JNI信息
        System.out.println("JNI: " + sun.misc.SharedSecrets.getJavaLangAccess().getJNIMethods().size());
    }
}

四、Nonheap的重要性

Nonheap对Java应用的运行也有很大的影响。

例如,Nonheap中的Direct Buffers如果不管控得当,会导致应用内存泄漏,最终导致JVM崩溃。

而且,PermGen Space也需要注意大小,因为如果PermGen Space不足,可能会导致“内部错误:Java堆空间溢出”,这是因为PermGen的比例比例比例如今应用的内存。

因此,掌握Nonheap的基本知识和调优方法是十分重要的。