堆空间
每个进程(JVM实例)拥有唯一的方法区和堆空间,拥有唯一的Runtime实例(基于饿汉式方式),线程共享进程的方法区和堆空间,每个线程拥有独立的程序计数器、本地方法栈和虚拟机栈。
- 一个JVM实例只存在一个堆内存,堆是Java内存管理的核心区域
- Java堆区在JVM启动的时候即被创建,其空间大小也就确定了,是JVM管理的最大一块存储空间
- 堆内存可以调节
- 堆可以处于物理上不连续的内存空间中,但在逻辑上是连续的
- 所有的线程共享Java堆,在这里还可以划分私有的缓冲区(Thread Local Allocation Buffer,TLAB)
- Java虚拟机规范中对Java堆的描述是:所有对象实例及数组都应该在运行时分配在堆上
- “几乎”所有的对象实例都在这里分配内存 – 从实际使用角度看
- 数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置
- 在方法结束后,堆中的对象不会马上移除,仅仅在垃圾收集的时候才会被移除
- 堆是GC执行垃圾回收的重点区域
public class SimpleHeap {
private int id;
public SimpleHeap(int id) {
this.id = id;
}
public void show() {
System.out.println("My ID is:" + id);
}
public static void main(String[] args) {
SimpleHeap s1 = new SimpleHeap(1);
SimpleHeap s2 = new SimpleHeap(2);
}
}
堆内存细分
- Java7及之前堆内存逻辑上分为三个部分:新生区+养老区+永久代
- Young Generation Space 新生代 Young/New
- 划分为Eden区和Survivor区
- Tenure Generation Space 养老区 Old/Tenure
- Permanent Space 永久代 Perm
- Young Generation Space 新生代 Young/New
- Java8及之前堆内存逻辑上分为三个部分:新生区+养老区+元空间
- Young Generation Space 新生代 Young/New
- 划分为Eden区和Survivor区
- Tenure Generation Space 养老区 Old/Tenure
- Meta Space 元空间 Meta
约定:新生区<->新生代<->年轻代 养老区<->老年区<->老年代 永久区<->永久代
- Young Generation Space 新生代 Young/New
堆空间大小设置
- Java堆区用于存储Java对象实例,堆的大小在JVM启动时就已经设定好了,可以通过"-Xmx"和“-Xms”来进行设置
- -Xms用于表示堆区的起始内存,等价于-XX:InitialHeapSize
- -Xmx则用于表示堆区的最大内存,等价于-XX:MaxHeapSize
- 一旦堆区中的内存大小超过"-Xmx"所指定的最大内存时,将会抛出OutOfMemoryError异常
- 通常会将-Xms和-Xmx两个参数配置相同的值,目的为了能够在Java垃圾回收机制清理完堆后不需要重新分隔计算堆区的大小,从而提高性能
- 默认情况下,初始内存大小:物理电脑内存大小/64,最大内存大小:物理电脑内存大小/4
/**
* 1.设置内存大小
* -Xms用来设置堆空间(年轻代+老年代)的初始内存大小
* -X 是JVM运行参数
* ms:memory start
* -Xmx用来设置堆空间(年轻代+老年代)的最大内存大小
* 2.默认堆空间大小
* 默认情况下,初始内存大小:物理电脑内存大小/64,
* 最大内存大小:物理电脑内存大小/4
* 3.手动设置 -Xms600m -Xmx600m
* 开发中建议将初始堆内存和最大堆内存设置成相同值
* 4.查看设置参数
* 1) jps | jstat -gc pid
* 2)-XX:+PrintGCDetails(在执行时添加参数)
*/
public class HeapSpaceInitial {
public static void main(String[] args) {
//返回Java虚拟机堆内存大小
long initialMemory = Runtime.getRuntime().totalMemory()/1024/1024;
//返回Java虚拟机试图使用的最大内存量
long maxMemory = Runtime.getRuntime().maxMemory()/1024/1024;
System.out.println("-Xms:" + initialMemory + "M");
System.out.println("-Xmx:" + maxMemory + "M");
System.out.println("系统内存大小:" + initialMemory * 64 / 1024 +"G");
System.out.println("系统内存大小:" + maxMemory * 4 / 1024 +"G");
}
}
//运行结果--计算单位1000
-Xms:489M
-Xmx:7246M
系统内存大小:30G
系统内存大小:28G
//jps/jstat -gc pid查看内存使用情况
C:\Users\Administrator\IdeaProjects\jvm\target\classes\com\chapter05>jps
3696 KotlinCompileDaemon
4832 Jps
10680 Launcher
10872 RemoteMavenServer36
8668
8716 HeapSpaceInitial
C:\Users\Administrator\IdeaProjects\jvm\target\classes\com\chapter05>jstat -gc 8716
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
21504.0 21504.0 0.0 0.0 131072.0 10485.8 348160.0 0.0 4480.0 770.4 384.0 75.9 0 0.000 0 0.000 0.000
-----------------------------------------------------------------------------------------------------------------------
//添加-XX:+PrintGCDetails
Heap
PSYoungGen total 152576K, used 10486K [0x0000000716300000, 0x0000000720d00000, 0x00000007c0000000)
eden space 131072K, 8% used [0x0000000716300000,0x0000000716d3d8b8,0x000000071e300000)
from space 21504K, 0% used [0x000000071f800000,0x000000071f800000,0x0000000720d00000)
to space 21504K, 0% used [0x000000071e300000,0x000000071e300000,0x000000071f800000)
ParOldGen total 348160K, used 0K [0x00000005c2800000, 0x00000005d7c00000, 0x0000000716300000)
object space 348160K, 0% used [0x00000005c2800000,0x00000005c2800000,0x00000005d7c00000)
Metaspace used 3491K, capacity 4498K, committed 4864K, reserved 1056768K
class space used 387K, capacity 390K, committed 512K, reserved 1048576K
OutOfMemory事例
public class OOMTest {
public static void main(String[] args) {
List<Picture> list = new ArrayList<>();
while (true) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(new Picture(new Random().nextInt(1024 * 1024)));
}
}
}
class Picture {
private byte[] pixels;
public Picture(int length) {
this.pixels = new byte[length];
}
}
//执行结果
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.chapter06.Picture.<init>(OOMTest.java:30)
at com.chapter06.OOMTest.main(OOMTest.java:20)