定义
- 一个进程对应一个jvm实例,一个jvm实例有一个运行时数据区,运行时数据库拥有一个堆,方法区,多个线程拥有多个虚拟机栈,程序计数器,本地方法栈
- 在jvm启动的时候被创建,其空间大小也确定了,是jvm管理的最大一块内存空间
- 堆内存大小是可以调节的
- 可以在物理上不连续,但在逻辑上要是连续的
- 所有的线程都共享堆,但还可划分线程私有的缓冲区TLAB
- 几乎所有的对象和数组都会分配到推上
- 数组和对象可能永远不会存储在栈上,在栈保存着引用,指向堆的内存位置。
- 在方法结束后,堆中的对象不会马上被移除,只有在垃圾回收的时候才会被清除
- 堆是垃圾收集器(GC)执行垃圾回收的重点区域
下面我们以一小段代码来展示一下对象的创建在字节码中的分配情况:
package com.lydon.test;
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);
int[] arr=new int[10];
Object[] objects=new Object[10];
}
}
新创建的对象s1和s2在虚拟机栈中保存的是对应堆内存的引用
字节码中的new就是创建对象
堆内存结构划分的变化
jdk1.7及之前将堆从逻辑上分为新生区,老年区,永久区,jdk1.8及之后分为新生区,老年区,元空间。
实际上-Xmx(堆的最大内存大小) 和-Xms(堆空间的初始内存大小,memory start)的配置项只影响了新生区和老年区,比如配置了-Xms10m -Xmx10m
新生代+老年代=10m
默认堆的大小
如果不手动设置堆的大小,则
默认的初始堆大小:物理电脑内存大小/64
默认的最大内存大小:物理电脑内存大小/4
代码中可以通过Runtime(运行时数据区的实例)去获取堆大小情况:
package com.lydon.test;
public class HeapSpaceInitial {
public static void main(String[] args) {
//返回jvm中堆内存总量
long initMemory=Runtime.getRuntime().totalMemory()/1024/1024;
//返回jvm中试图使用的最大堆内存总量
long maxMemory=Runtime.getRuntime().maxMemory()/1024/1024;
System.out.println("-Xms:"+initMemory+"m");
System.out.println("-Xmx:"+maxMemory+"m");
System.out.println("系统总内存大小:"+initMemory*64/1024);
System.out.println("系统总内存大小:"+maxMemory*4/1024);
}
}
查看jvm进程堆空间大小
方法一:
在bin中使用jps查看当前jvm的进程,然后再用jstat -gc 进程id查看jvm的堆内存情况
方法二:
在jvm参数中,配置-XX:+PrintGCDetails