堆
对于GC垃圾回收,主要在伊甸园和养老区。
假设内存满了,OOM,堆内存不够!java.lang.OutOfMemoryError: java heap space
在JDK8以后,永久存储区改了名字(元空间);
什么是堆内存?
JVM中的堆内存是一个非常关键的内存区域。用于存储对象实例和数组。堆内存是所有线程共享的,并且是垃圾回收的主要目标区域。堆内存通常可以分为多个区域,主要包括 新生代(Young Generation)、老年代(Old Generation)、和永久代(PermGen) (或元空间Metaspace,在JDK8以后,永久代被替代为元空间),这些区域的管理和垃圾回收策略各不相同。
堆内存的特征:
- 共享内存区域:所有线程共享堆内存。它不属于任何特定的线程,因此不同线程之间可以访问堆上的对象。
- 垃圾回收的主战场:堆内存中存储的对象在垃圾回收过程中会被检查、标记并回收。
1. 新生代(Young Generation)
新生代是堆内存的一个区域,专门用来存放 新创建的对象。大多数对象都会在这里诞生,然而大部分对象在短时间内会被回收。
新生代被进一步分为 三个区:
- Eden 区:是新生代的主区域,用于存放新创建的对象。
- From Survivor 区:用于存放从 Eden 区和另一 Survivor 区(To Survivor)晋升过来的对象。
- To Survivor 区:与 From Survivor 区配对,也是新生代的一个区域,存放一些暂时存活的对象。
新生代的垃圾回收
- 新生代的垃圾回收称为 Minor GC,通常发生在 Eden 区 满时。
- Minor GC 比较频繁,但通常是快速的,因为它只涉及新生代的回收。
- 大多数对象会在新生代经历若干次回收后被提升到老年代。
新生代的特点:
- 短生命周期:新生代的对象大多是短命的,许多对象创建后很快就会被垃圾回收。
- 垃圾回收频繁:由于新生代对象的生命周期短,垃圾回收发生得频繁,回收速度也较快。
2. 老年代(Old Generation)
老年代是堆内存的另一部分,用于存放存活时间较长的对象。这些对象通常在新生代经过多次垃圾回收后,由于长时间存活而被晋升到老年代。
老年代的垃圾回收称为 Major GC 或 Full GC。它通常比 Minor GC 更耗时,因为它涉及到整个堆的回收,包括新生代和老年代。
老年代的特点:
- 生命周期长:老年代的对象是那些存活了较长时间的对象,通常它们较为稳定,不会频繁被销毁。
- 垃圾回收较少:老年代的垃圾回收比较少发生,但每次发生时会比较耗时,因为老年代中的对象往往占用大量内存空间。
老年代晋升:
- 对象在新生代经历若干次 Minor GC 后,如果仍然存活,会被晋升到老年代。
- 对象晋升到老年代的条件和机制是基于其存活的年龄(即对象存活的 GC 次数)。
3. 永久代(PermGen)与元空间(Metaspace)
在 JDK 8 之前,永久代(PermGen) 是堆内存的一部分,用于存储 类信息、方法信息 和 常量池 等与类加载相关的数据。PermGen 是固定大小的,不受堆内存的动态调整限制,因此在运行过程中容易发生 OutOfMemoryError: PermGen space 错误。
永久代的特点:
- 固定大小:永久代的大小是固定的,无法动态扩展。
- 存储类信息:它主要存储类的结构信息(如字段、方法、常量池等)。
- 常常发生内存溢出:如果加载的类太多,或者常驻内存的类没有及时被回收,永久代空间就会耗尽,导致内存溢出。
元空间(Metaspace):
- 从 JDK 8 开始,永久代 被 元空间(Metaspace) 替代。元空间不再是 JVM 堆内存的一部分,而是直接使用本地内存(Native Memory)。
- 元空间的大小是动态可扩展的,不再受到固定大小的限制。
- 元空间的容量受限于操作系统的本地内存,而不再受 JVM 堆内存的限制。
元空间的特点:
- 动态大小:JVM 可以动态调整元空间的大小,受限于物理内存。
- 存储类的元数据:与永久代一样,元空间存储类的元数据,包括类信息、方法信息等。
- 可以通过参数调整:可以通过 JVM 参数
-XX:MaxMetaspaceSize来设置元空间的最大大小。
4.堆内存管理的参数
- -Xms:设置堆的初始大小。
- -Xmx:设置堆的最大大小。
- -Xmn:设置新生代的大小。
- -XX:MaxMetaspaceSize:设置元空间的最大大小。
- -XX:PermSize:JDK 8 之前用于设置永久代的初始大小。
- -XX:MaxPermSize:JDK 8 之前用于设置永久代的最大大小。
模拟堆内存OOM
默认情况下 分配的总内存是系统的1/4 ,而初始化的内存: 1/64
IDEA中设置堆内存大小操作
-Xms1024m -Xmx1024m --XX:+PrintGCDetails
初始值与最大值设成一致 --XX:+PrintGCDetails 是打印GC去除垃圾的细节
public class Demo {
public static void main(String[] args) {
//返回虚拟机试图使用的最大内存
long max = Runtime.getRuntime().maxMemory();
//返回JVM的初始化内存
long total = Runtime.getRuntime().totalMemory();
System.out.println("max:"+max+"字节\t" + (max/(double)1024/1024)+"MB");
System.out.println("total:"+total+"字节\t" + (total/(double)1024/1024)+"MB");
}
}
public class Demo {
public static void main(String[] args) {
//返回虚拟机试图使用的最大内存
long max = Runtime.getRuntime().maxMemory();
//返回JVM的初始化内存
long total = Runtime.getRuntime().totalMemory();
System.out.println("max:"+max+"字节\t" + (max/(double)1024/1024)+"MB");
System.out.println("total:"+total+"字节\t" + (total/(double)1024/1024)+"MB");
String srt = "java";
while(true){
srt += srt + new Random().nextInt(999999999)+new Random().nextInt(999999999);
}
}
}