JVM听课随记 04 堆 Heap

4.1 堆体系结构

一个JVM只存在一个堆内存,堆内存的大小是可以可以调节的,类加载器读取了类文件之后,需要把类,方法,常量变量放到堆内存中,保持所有引用类型的真实信息;

其中堆内存分位三部分 :新生+养老+永久

注意:Java8之后 永久区就变成了元空间

在这里插入图片描述

再还有注意的点就是 :

堆内存在逻辑上分为新生+养老+永久 ;在物理上分为新生+养老

4.2 对象在堆中的生命周期

(1) 首先,新生区是类的诞生,成长和消亡的区域。一个类在这里被创建并使用,最终被垃圾回收器收集,结束生命。

(2)然后所有类都是在Eden Space区被new出来的。而当Eden Space用完时程序需要又要创建对象,JVM垃圾回收器则会将Eden Space中不再被其他对象所引用的对象进行销毁,也就是垃圾回收(Minor GC)。此时的GC可以认为是轻量级GC

(3)然后将Eden Space剩余的未被回收的对象移动到Survivor 0 Space,以此往复,直到Survivor 0 Space也慢了,再对Survivor 0 Space进行垃圾回收,剩余未被回收的对象,则再移动到Survivor 1 Space,Survivor 1 Space也满了的话,再移动至Tenure Generation Space

(4)最后如果Tenure Generation Space也满了的话,那么这个时候就会被垃圾回收(Major GC or Full GC)并将该区的内存清理。此时的GC可以认为是重量级GC。如果Tenure Generation Space被GC垃圾回收之后,依旧处于占满状态的话,就会产生我们场景的OOM异常,即OutOfMemoryError

4.3 Minor GC的过程

Survivor 0 Space,也叫做幸存者0区,也叫from区

Survivor 1 Space,也叫做幸存者1区,也叫to区

注意:from区和to区的名分和位置是不固定的。是相互交换的,意思是说,在每次GC之后,两者都会进行交换,谁空谁为to区

接下来,继续讲的更明白  这时候需要记住两个比例

新生区中三者的比例 8:1:1  新生区和养老区的比例为1:2

在这里插入图片描述

(1) Eden Spacefrom复制到to,年龄+1。

首先当Eden Space满的时候会触发第一次GC,把还活着的对象复制到from区。而当Eden Space再次触发GC的时候,会扫描Eden Spacefrom区,对这两个区进行垃圾回收,经过此次回收后依旧存活的对象,则直接复制到to区

(注意只要产生GC Eden Space必会清空

注意:如果对象的年龄已经达到老年的标准,则移动至老年代区,同时把这些对象的年龄加+1

(2)清空Eden Spacefrom

然后清空Eden Space和from区中的对象,此时from是空的

(3)fromto互换

最后,from和to进行互换,原from成为下一次GC时的to,原to成为下一次GC时的from。部分对象会在from和to中来回进行交换复制,如果交换15次(由JVM参数MaxTenuringThreshold决定,默认15),最终依旧存活的对象就会移动至老年代。

总结一句话,GC之后有交换,谁空谁是to。

这样也是为了保证内存中没有碎片,所以Survivor 0 SpaceSurvivor 1 Space有一个要是空的。

4.4 HotSpot虚拟机的内存管理

 注意:不同对象的生命周期不同,其中98%的对象都是临时对象,即这些对象的生命周期大多只存在于Eden区

实际而言,方法中(Method Aera)和堆一样是各个线程共享的内存区域,它是存储虚拟机加载的:类信息+普通常量+静态常量+编译器编译后的代码等等。虽然JVM规范将方法区描述为堆的一个逻辑部分,但它却还有一个别名叫做Non-Heap(非堆内存),目的就是要和堆区分开

对于HotSpot虚拟机而言,很多开发者习惯将方法区称为 “永久代(Permanent Gen)” 。但严格来说两者是不同的,或者说只是使用永久代来实现方法区而已,永久代是方法区(可以理解为一个接口interface)的一个实现,JDK1.7的版本中,已经将原本放在永久代的字符串常量池移走。(字符串常量池,JDK1.6在方法区,JDK1.7在堆,JDK1.8在元空间。)


在这里插入图片描述

 如果没有明确指明,Java虚拟机的名字就叫做HotSpot

4.4 永久区

 永久区是一个常驻内存区域,用于存放JDK自身所携带的class,Interface的元数据(也就是上面文中的提到的rt.jar包等),也就是说它存储的是运行环境所必须的类信息,被装载此区域的数量是不会被垃圾回收器回收掉的,关闭JVM才会释放此区域的所占用的内存。

(1) JDK 1.7

在这里插入图片描述

 (2) JDK 1.8

在这里插入图片描述

在JDK1.8中,永久代已经被移除,被一个称为元空间的区域所取代。元空间的本质和永久代类似。元空间和永久代的最大区别在于:永久代所使用的JVM的堆内存,但是java8以后的元空间并不存在虚拟机而是使用物理内存。

因此,默认情况下,元空间的大小仅受本地内存限制。

类的元数据方法 native memory ,字符串池和类的静态放入Java堆中,这样可以加载多少类的元数据就不再由MaxPermSize控制, 而由系统的实际可用空间来控制。

4.5 堆参数调优

在进行调优之前。我们在代码里可以获取到jvm的信息

public class JVMMemory {
    public static void main(String[] args) {
        // 返回 Java 虚拟机试图使用的最大内存量
        long maxMemory = Runtime.getRuntime().maxMemory();
        System.out.println("MAX_MEMORY = " + maxMemory + "(字节)、" + (maxMemory / (double) 1024 / 1024) + "MB");
        // 返回 Java 虚拟机中的内存总量
        long totalMemory = Runtime.getRuntime().totalMemory();
        System.out.println("TOTAL_MEMORY = " + totalMemory + "(字节)、" + (totalMemory / (double) 1024 / 1024) + "MB");
    }
}

运行结果如下:

在这里插入图片描述

 这个3607.5MB243.5MB是怎么算出来的?看下图就明白了,虚拟机最大内存为物理内存的1/4,而初始分配的内存为物理内存的1/64。
在这里插入图片描述

 IDEA中如何配置JVM内存参数?在【Run】->【Edit Configuration…】->【VM options】中,输入参数-Xms1024m -Xmx1024m -XX:+PrintGCDetails,然后保存退出。

注意:JVM的初始内存和最大内存一般怎么分配

初始内存和最大内存一定是一样大,理由是避免GC和应用程序争抢内存,进而导致内存忽高忽低产生停顿。

运行结果如下:

在这里插入图片描述

 4.6 堆溢出 OutOfMemoryError

现在我们来演示一下OOM,首先把堆内存调成10M后,再一直new对象,导致Full GC也无法处理,直至撑爆堆内存,进而导致OOM堆溢出错误,程序及结果如下:

import java.util.Random;
public class OOMTest {
    public static void main(String[] args) {
        String str = "Atlantis";
        while (true) {
            // 每执行下面语句,会在堆里创建新的对象
            str += str + new Random().nextInt(88888888) + new Random().nextInt(999999999);
        }
    }
}


在这里插入图片描述

注意:如果出现java.lang.OutOfMemoryError: Java heap space异常,说明Java虚拟机的堆内存不够,造成堆内存溢出。原因有两点:
①Java虚拟机的堆内存设置太小,可以通过参数-Xms和-Xmx来调整。
②代码中创建了大量对象,并且长时间不能被GC回收(存在被引用)。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值