JVM类加载过程和GC机制

Posted 3 ERROR(s)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM类加载过程和GC机制相关的知识,希望对你有一定的参考价值。

文章目录

一、JVM运行时数据区

1.堆区(线程共享)

如果是基本数据类型,看他是局部变量还是成员变量,局部变量在栈上开辟空间,成员变量在堆区开辟空间。
如果是引用数据类型,JVM在堆中创建对象,对象的引用存在虚拟机栈上的局部变量表中。

4.方法区(元数据区)(线程共享)

里面放的都是类对象

  • 包含了这个类的各种属性的名字,类型,访问权限
  • 包含了这个类的各种方法的名字,参数类型,访问权限,以及二进制代码
  • 包含这个类的static成员
    对于 HotSpot 来说,JDK 8方法区的内存属于本地内存,这样方法区空间的大小就不在受 JVM 最大内存的参数影响了,而是与本地内存的大小有关。
    JDK 8 中将字符串常量池移动到了堆中。

2.Java虚拟机栈(线程私有)

Java 虚拟机栈的作用:Java 虚拟机栈的生命周期和线程相同,Java 虚拟机栈是用来描述 Java 方法执行的
内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数
栈、动态链接、方法出口等信息。咱们常说的堆内存、栈内存中,栈内存指的就是虚拟机栈。

3.本地方法栈(线程私有)

本地方法(native method)指的是JVM内部的方法(C++写的)

5.程序计数器(线程私有)

.java代码 =》.class(二进制字节码,里面就是一些指令) =》放到内存中 =》每条指令都有自己的地址=》 CPU执行指令就要从内存中取除地址,然后再在CPU上执行

二、类加载过程


类加载就是从加载到初始化这个过程

1.加载:通过全限定名称找到这个类的二进制字节流,在内存中生成一个代表这个类的Java.long.Class对象作为这个类的各种访问数据的入口
2.链接

  • ( 1 )验证 验证这个.Class文件包含的信息符合《Java虚拟机规范》
  • ( 2 )准备 给类对象成员分配空间并且初始化为0。
  • ( 3 )解析 初始化字符串常量
    3.初始化 初始化static变量,执行static代码块

双亲委派机制

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,因此所有的加载请求最 终都应该传送到最顶层的启动类加载器中,如果父类中找不到这个类,就交给子类加载器完成。

  • 启动类加载器
  • 应用程序类加载器
  • 自定义类加载器

双亲委派机制优点

1.避免重复加载类,这样一套机制的目的就是创造一个优先级顺序
2.保证Java核心API的安全性,因为有些类是用户自己写的,不能保证他的安全性

三、垃圾回收

1.回收的是哪些内存

  • 方法区
    其他的内存区都是随着线程的销毁能自动释放了。
    我们此处讨论的垃圾回收 具体是指堆内存的回收。

2.死亡对象判断的算法

(1).引用计数(Java根本不用这个)

给对象增加一个引用计数器,每当有一个地方引用他的时候,计数器自增;当引用失效的时候计数器自减,当计数器为0的时候我们就认为这个对象不能再被使用了,判断他“死亡”。
优点:规则简单,实现方便,判定高效。
缺点:如果对象很多,但是引用少的情况加一个int型的计数器会导致得不偿失,内存压力大。他就适合对象少,引用多的情况。
还有一个致命的缺点,循环引用可能导致计数器失效。

(2).可达性分析

通过一系列我们称之为GCRoost 的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为"引用链",当一个对象和引用链没有任何相连的时候,我们就可以说这个对象是不可用的。
GCRoots对象可以包含以下几种:

  • 方法区中静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中Native引用的对象
  • 虚拟机栈中引用的对象

四种引用情况:

  • 强引用:只要强引用存在,他就不可能回收被引用的对象。
  • 软引用:有用但不必须,如果要发生内存溢出了,JVM就会把他们回收了,如果经过这次回收还是空间不足才会抛出溢出异常。
  • 弱引用:被弱引用关联的对象只能生存到下一次垃圾回收发生前,下一次人家开始回收,不管内存溢出不溢出,它一定被回收。
  • 虚引用:不能通过虚引用获得一个对象实例,他存在的意义就是这个对象被回收的时候能收到一个系统通知。

3.垃圾回收策略

(1) 标记-清除算法

首先标记所有要回收的对象,然后再进行统一回收。

缺点:

  • 效率非常低,不管是标记还是清除,
  • 内存碎片化问题, 回收之后的内存空间不连续,如果有较大的对象要存入的话就要提前进行二次回收了。

(2) 复制算法

它将可用内存按照大小划分为相等的两块,每次只用其中的一块,在标记完清除的对象后,就把这片区域还存活的对象复制到另外一边内存上去,然后回收的时候把当前内存整体回收。
优点:解决了内存碎片化的问题
缺点:每次只有一半内存可用,当回收的对象少的时候这种办法显然不合适,他适合对象被快速回收,并且对象不多需要的内存不大。

(3)标记-整理

复制收集算法在对象存活率较高时会进行比较多的复制操作,效率会变低。因此在老年代一般不能使用复制算法。
为了解决这个问题,我们对需要清除的对象先标记,再清除,然后让所有存活的对象向一端移动。

(4)分代算法

  • 新生代:一般对象创建后都会进入新生代
  • 老年代:该对象经过(15)次内存回收之后会变为老年代
  1. 当Eden区满的时候,会触发第一次Minor gc,把还活着的对象拷贝到Survivor From区;当
    Eden区再次触发Minor gc的时候,会扫描Eden区和From区域,对两个区域进行垃圾回收,经过
    这次回收后还存活的对象,则直接复制到To区域,并将Eden和From区域清空。
  2. 当后续Eden又发生Minor gc的时候,会对Eden和To区域进行垃圾回收,存活的对象复制到
    From区域,并将Eden和To区域清空。
  3. 部分对象会在From和To区域中复制来复制去,如此交换15次(由JVM参数
    MaxTenuringThreshold决定,这个参数默认是15),最终如果还是存活,就存入到老年代
    4.如果某个对象非常大,占的内存大于生存区的大小,就将它直接放入老年代。老年代如果满了就会发生Full GC

以上是关于JVM类加载过程和GC机制的主要内容,如果未能解决你的问题,请参考以下文章

36.JVM内存分哪几个区,每个区的作用是什么如和判断一个对象是否存活java垃圾回收机制垃圾收集的方法有哪些java类加载过程类加载机制双亲委派Minor GC和Major GC

JVM结构GC工作机制详解

Java虚拟机(JVM)与垃圾回收机制(GC)的详解

jvm类加载机制

JVM架构和工作原理及GC工作机制

JVM理论:(三/5)类加载机制