八、运行时内存篇——堆


1、核心概述

  • 一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域。
  • Java 堆区在JVM启动的时候即被创建,其空间大小也就确定了。是JVM管理的最大一块内存空间
  • 堆内存的大小是可以调节的。
  • 《Java虚拟机规范》规定,堆可以处于物理上不连续的内存空间中但在逻辑上它应该被视为连续的
  • 堆,是GC ( Garbage collection,垃圾收集器)执行垃圾回收的重点区域
  • 在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除

(1)对象都分配在堆上?

是的。特殊情况“栈上分配”,发生JVM性能优化时,将对象分配在栈上,因为栈不会被GC,并且栈执行效率快。

(2)所有的线程都共享堆?

所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer,TLAB)。

2、堆的内部结构

 堆内存逻辑上分为三部分:新生区 + 养老区 + 元空间

Young Generation Space 新生区,又细分为Eden区和Survivor区(S0和S1)

Tenure Generation Space  养老区

Meta Space 元空间

年轻代与老年代

1、存储在JVM中的Java对象可以被划分为两类

  • 一类是生命周期较短的瞬时对象,这类对象的创建和消亡都非常迅速
  • 另外一类对象的生命周期却非常长,在某些极端的情况下还能够与JVM的生命周期保持一致。

2、Java堆区进一步细分的话,可以划分为年轻代(YoungGen)和老年代(OldGen)。
3、其中年轻代又可以划分为Eden空间、Survivora空间和Survivor1空间(也叫做from区、to区)。
4、几乎所有的Java对象都是在Eden区被new出来的大对象直接在老年代中创建
5、绝大部分的Java对象的销毁都在新生代进行了。

3、如何设置堆内存大小

1、Java堆区用于存储Java对象实例,那么堆的大小在JVM启动时就已经设定好了,大家可以通过选项“-Xms”和”-Xmx”来进行设置。

  • -Xms用于表示堆区的起始内存,等价手-XX:InitialHeapsize
  • -Xmx用于表示堆区的最大内存,等价于-XX:MaxHeapsize

2、一旦堆区中的内存大小超过“-Xmx”所指定的最大内存时,将会抛出OutOfMemoryError异常。

3、通常会将-Xms和-Xmx两个参数配置相同的值,其目的是为了能够在java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小,从而提高性能。

  • heap默认最大值计算方式:如果物理内存少于192M,那么heap最大值为物理内存的一半。如果物理内存大于等于1G,那么heap的最大值为物理内存的1/4
  • heap默认最小值计算方式:最少不得少于8M,如果物理内存大于等于1G,heap默认最小值为物理内存的1/64,即1024/64=16M。最小堆内存在jvm启动的时候就会被初始化。

4、堆空间大小在实际开发中一般设置为2GB。并不是设置的越大越好,可能会影响其他应用,比如ES。

(1)如何设置新生代与老年代比例?

(2)如何设置Eden、幸存者区比例?

(3)OOM举例

(4)参数设置总结

4、对象分配金句

5、解释MinorGC、MajorGC、FullGC

6、OOM如何解决

7、堆空间分代思想

8、快速分配策略:TLAB

JVM