JVM将内存区域划分为方法区,堆,虚拟机栈,本地方法栈,程序计数器五块区域。

如下图所示:




java 堆内存占用不段增加 java堆内存分配比例_堆内存

JVM内存结构



比较常见的是堆内存和栈内存(虚拟机栈)。

方法区和堆,是线程共享的内存区域,其余三块是线程独享区域,至于为什么分为线程共享和非线程共享,在后续章节中会提及到,请加关注。

堆内存大小可以通过-Xms和-Xmx来进行控制。

其中-Xms表示启动时申请的最小内存,默认为物理内存的1/64,

-Xmx表示可申请的最大内存,默认为物理内存的1/4。

如果剩余的堆内存小于40%时,jvm会自动扩大内存到-Xmx值。

可以通过-XX:MinHeapFreeRation选项来定义比例。

如果剩余堆内存大于70%时,jvm对减小堆内存到-Xms值。

可以通过XX:MaxHeapFreeRation选项来定义比例。

在实际项目中,为了避免JVM频繁调整堆内存大小,一般来讲,-Xms与-Xmx的值设成一样。

堆内存 = 新生代+老生代+持久代

新生代

主要是用来存放新生的对象。一般占据堆的1/3空间,新生代又分为 Eden区、ServivorFrom、ServivorTo三个区。新生代可能会频繁触发MinorGC进行垃圾回收。关于MinorGC的过程,在后续章节中会提及到,请加关注。

老年代

老年代的对象比较稳定,所以MajorGC不会频繁执行,MajorGC采用标记—清除算法,详细过程也会在后续章节中提到,请加关注。

永久代

指内存的永久保存区域,主要存放Class和Meta(元数据)的信息。GC不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的Class的增多而胀满,最终抛出OOM异常。在Java8之前,通常会出现这种情况。

Java8永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代.

元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,因此不会出现OOM异常。