1、堆Heap

一个JVM实例只存在一个堆内存,堆内存的大小是可以调节的,类加载器读取了类文件后,需要把类、方法、常变量放在堆内存中,保存所有引用类型的真实信息,以方便执行器执行,堆内存分为三部分: 新生区 养老区 永久区(JDK 7 之前叫永久区 JDK 8开始就叫元空间) 逻辑上是有着三个区域 但是物理上来说只有栈和堆

幸存区又可分为From区和To区

2、Heap堆中对象new之后的简单过程

简单理解: 新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。新生区又分为两部分:伊甸区、幸存者区、所有的类都是在伊甸区被new出来的。幸存者区有两个,0区和1区。当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC 或者称为YGC),将伊甸园区中的不再被其他对象引用的对象进行销毁。然后伊甸园中的剩余对象移动到幸存0区。如果幸存0区也满了,则再堆该区进行垃圾回收,然后移动到1区。如果1区也满了再移动到养老区。若养老区也满了,那么这个时候会产生MajorGC(FullGC),进行养老区的内存清理。若养老区执行了FullGC之后发现依然无法进行对象的保存,就会产生OOM异常(OutOFMemoryError)

常量字符串在元空间的常量池

3、MinorGC过程(复制 清空 互换)

4、Sun HotSpot内存管理

分代管理: 不同对象的生命周期不同,百分之98的对象是临时对象 实际而言,方法区和堆一样,是各个线程共享的内存区域,它用于存储虚拟机加载的:类信息+普通常量+静态常量+编译器编译后的代码等等,虽然JVM规范将方法区描述为堆的一个逻辑部分,但它却还有一个别名叫做非堆(non-heap),目的就是要和堆分开 对于HotSpot虚拟机而言,很多开发者习惯性的将方法区称为“永久代”,但严格本质上来说两者不同,或者说使用永久代实现方法区而已,永久代是方法区的一个实现,JDK1.7的版本中已经将原本放在永久代的字符串常量池移走

5、堆参数管理

重要参数 JVM Heap -Xms参数 堆初始大小 默认为物理内存的64分之一 -Xmx 堆最大所占物理空间大小 默认为物理内存的4分之一 -Xmn 堆中新生区所占大小 --XX: +PintGCdetails 输出打印GC日志

永久区(Java7之前有): 永久存储区是一个常驻内存区域,用于存放JDK自身所携带的Class,Interface的元数据(比如JDBC注册的驱动类,Spring等注册的元数据都是这个范畴),也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM才会释放此区域所占内存。 元空间(Java 8) 在Java8中,永久代已经被移除,被一个称为元空间的区域所取代,其本质类似,其最大区别是永久代使用的jvm的堆内存,但是Java8以后的元空间并不在虚拟机中而是使用了本机物理内存。 因此,在默认情况下,元空间的大小仅受本地内存限制。类的元数据放入native memory 字符串常量池和类的静态变量放入java堆中,这样可以加载多少的元数据就不再由MaxPermSize控制,而是由系统实际可用空间来控制。

永久区和元空间区别: 在JDK7及以前,习惯上把方法区,称为永久代。JDK8开始,使用元空间取代了永久代。当年使用永久代,更容易导致Java程序更容易OOM。永久代仍然使用的是Java虚拟机的内存在JDK8中,类的元数据现在存储在本地内存中,这个空间被称为元空间。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代最大的区别在于:元空间不在虚拟机设置的内存中,而是使用本地内存。JDK7方法区使用的是虚拟机内存,同时将静态变量和字符串常量池搬移到了堆

JVM调参案例:


//查看当前JVM堆内存大小
public class Demo {
    public static void main(String[] args) {
        long maxMemory =Runtime.getRuntime().maxMemory();//返回Java虚拟机试图使用的最大内存
        long totalMemory=Runtime.getRuntime().totalMemory();//返回Java虚拟机中的内存总量
        System.out.println(maxMemory/(double)1024/1024);
        System.out.println(totalMemory/(double)1024/1024);
    }
}

输出结果:

可以自定义给堆初始化和堆最值参数进行设置,推荐两者相等,避免程序在运行过程中所占的内存忽高忽低,不稳定。 Idea调参方式如下 运行后输出:

GC日志规则

YGC规则:

FGC规则:

针对HotSpot VM的实现,它里面的GC其实准确分类只有两大种:

  • Partial GC:并不收集整个GC堆的模式
    • Young GC:只收集young gen的GC
    • Old GC:只收集old gen的GC。只有CMS的concurrent collection是这个模式
    • Mixed GC:收集整个young gen以及部分old gen的GC。只有G1有这个模式
  • Full GC:收集整个堆,包括young gen、old gen、perm gen(如果存在的话)等所有部分的模式。

Major GC通常是跟full GC是等价的,收集整个GC堆。但因为HotSpot VM发展了这么多年,外界对各种名词的解读已经完全混乱了,当有人说“major GC”的时候一定要问清楚他想要指的是上面的full GC还是old GC