八、运行时内存篇——堆
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。