1、堆空间的核心概述
分析演示实例:
代码块:
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[] arr1 = new Object[10];
}
}
对应的字节码分析:
堆空间的内部结构:
查看堆空间的具体细节:首先在运行的java程序进行虚拟机配置,配置参数:-XX:+PrintGCDetails,表示打印GC的具体细节,此后每次进行垃圾回收的时候,都会对堆空间中的新生代,老年代和元空间进行垃圾回收,并打印出回收日志信息。
从打印出来的GC日志信息可以看出,堆空间中包含了逻辑上的新生代、老年代和元空间,而新生代中又可以分为三个区域:伊甸园区、幸存者0区(from区)和幸存者1区(to区)。
2、设置堆内存大小和OOM(OutOfMemory:内存溢出)
手动设置堆的空间大小:
-Xms2g -Xmx2g:代表我们将初始堆内存和最大堆内存都设置为2g,在实际的开发中,都是将初始的堆内存和最大堆内存设置为一样的,如果不一样的话,导致堆内存进行频繁的进行扩容和缩减,系统压力增加。
OOM演示:OutOfMemoryError(内存溢出异常)
代码:
public class OutOfMemoryTest {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
while(true){
list.add(new Person(1));
}
}
}
class Person{
private int id;
public Person(int id) {
this.id = id;
}
}
垃圾回收器(GC)的日志信息:
垃圾回收器会在新生代进行YoungGC(轻GC),以及在老年代进行OldGC(重GC),在这个演示的代码中,gc在垃圾回收的时候,发现不管自己怎么进行垃圾回收,最终都回收不赢在堆内存创建对象的过程,导致堆内存溢出的问题。
3、年轻代和老年代
特别注意:在JVM官方文档中,规定了伊甸园区和幸存者0区(from区)和幸存者1区(to区)的占用大小为:8:1:1,可以通过-XX:SurvivorRatio这个参数进行调整比例,但是,通过参数查看可以计算得出实际上的比例不是默认的8:1:1,需要明确指出这个比值,-XX:SurvivorRatio=8,才能生效。
-XX:-UseAdaptiveSizePolicy:关闭自适应的内存分配策略。当需要开启自适应分配策略的时候就是:-XX:+UseAdaptiveSizePolicy
-Xmn:设置新生代的空间大小(一般不使用这个设置新生代的大小,都是通过NewRatio这个设置新生代和老年代的比例)
4、对象分配的过程
5、Minor GC、Major GC 、Full GC
6、堆空间的分代思想
7、内存分配策略
8、为对象分配内存
9、堆空间的参数总结
10、堆是分配对象存储的唯一选择吗?
总结:堆空间是对象分配的唯一方式,虽然我们可以通过开启逃逸分析让只在方法内部被使用的对象(未发生逃逸的对象)分配在栈上,但是这个过程实际上是标量替换/对象分离的方式实现的,使得对象被分解成标量存储在栈空间,实际上对象并不是以完整的形式存在在栈空间的。因为对象要能完整保存只有保存在堆空间。