2.4堆
一个JVM实例中只存在一个堆区,堆也是Java内存管理的核心区域。
堆区的唯一目的就是存放对象实例,几乎所有的对象实例以及数据都在这里进行分配内存。
Java堆是垃圾收集器管理的主要区域,因此也被称为GC堆。
(1)堆的内存划分
- 新生代
- Eden
- Survivor
- from
- to
- 老年代
- 元空间(永久代)
(2)设置堆内存大小
- -Xmx 用来表示堆的起始内存 , 默认情况下,初始堆内存大小为: 电脑内存大小 / 64
- -Xms 用来表示堆的最大内存 , 默认情况下,最大堆内存大小为: 电脑内存大小 / 4
(3)堆区常见的OOM
java.lang.OutOfMemoryError: GC Overhead Limit Exceeded
: 当 JVM 花太多时间执行垃圾回收并且只能回收很少的堆空间时,就会发生此错误。java.lang.OutOfMemoryError: Java heap space
:假如在创建新的对象时, 堆内存中的空间不足以存放新创建的对象, 就会引发此错误。Permgen space
:永久代已满,通常是加载的class数目太多或者是体积太大、
对象分配过程
- new 的对象先存放在eden区,但是伊甸园区有大小限制
- 当eden空间填满时,程序有需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁,再加载新的对象放到伊甸园区
- 然后将伊甸园中的剩余对象移动到幸存者0区
- 如果再次触发垃圾回收,此时上次幸存下来的放到幸存者0区,如果没有i回收,就会放到幸存者1区
- 默认是15次回收标记就会进入老年代
- 在老年代内存不足时,再次触发Major GC,进行老年代的内存清理
- 如果老年代执行了Major GC之后发现依然无法进行对象保存,就会产生OOM异常
内存分配策略
- 优先分配到伊甸园区
- 大对象直接分配到老年代
- 长期存活的对象分配到老年代
- 如果survivor区中相同年龄的所有对象大小总和大于survivor空间的一半,年龄大于或者等于该年龄的对象可以直接进入老年代
- 空间分配担保