• JVM学习与总结一


    一、类加载机制

    什么是类加载

    类加载就是将 .class 文件的二进制数据读取到内存中,将其放在运行时数据区的方法区内,然后在区创建一个 java.lang.Class对象,用来封装在方法区内数据的数据结构。类加载的最终产品是位于堆区中的 Class对象,它向程序员提供了访问方法区内数据结构的接口。


    类的生命周期

    注意:各个周期只是以这个顺序开始而已,过程和结果很可能不会按照此顺序进行!

    加载-->验证-->准备-->解析-->初始化-->使用-->卸载

    • 加载:查找并加载类的二进制数据,在堆区中创建一个 java.lang.Class对象

    • 验证:验证文件格式、元数据、字节码、符号引用

    • 准备:给类的静态变量分配内存,并初始化默认值(0或者" ")

    • 初始化:给类的静态变量正确的初始值

    • 使用:new 对象实例使用

    • 卸载:对象无引用时,执行垃圾回收


    类加载器

    下面是几种类加载器及各自负责加载类库的描述:

    1. 启动类加载器:Bootstrap ClassLoader

      • jdk/jre/lib 目录下的类库

      • 被 -Xbpptclasspath 参数指定的路径中的类库

      • 并且能被虚拟机识别的类库

    2. 扩展类加载器:Extension ClassLoader

      • jdk/jre/lib/ext 目录下的类库

      • 由 java.ext.dirs系统变量指定的路径中的所有类库(如:java.* 开头的类)

    3. 应用程序类加载器:Application ClassLoader

      • 加载用户类路径(ClassPath)指定的类

    双亲委派模型

    1. 全盘负责

      当一个类加载器要加载某个类时,那么这个类所依赖和引用的其他类也由这个类加载器负责一块载入

      除非规定显示使用另一个类加载器载入

    2. 父类委托

      先让父类加载器试图加载该类,只有父类加载器无法加载该类时才尝试才从自己的路径中加载该类

    3. 缓存机制

      保证所有加载过的类都被缓存,在程序中需要使用某个类时,类加载器先去缓存区寻找该类,
      如果缓存区内不存在,系统才会去加载该类,并转换成 java.lang.Class 对象存入缓存区,

      这就是为什么修改了 java文件后,需要重启jvm,程序的修改才会生效


    所以什么是双亲委派模型?

    这里举个例子:
    现在有一个类加载器 A,某时刻A收到了一个类加载的请求,这时它不会立刻去加载,
    而是先将这个请求委托给 它的父类加载器,如果父类加载器还有父类那就再委托,直到委托到最顶层的“祖宗加载器”为止。
    由这个“祖宗”去处理这个类加载的请求,如果连“祖宗”加载器都不能加载,这时 A才会自己去尝试加载

    这就是双亲委派模型



    二、JVM内存结构

    都有哪些内存结构

    线程共享:java堆、方法区

    线程私有:java栈、本地方法栈、程序计数器

    1. java堆(共享

      java虚拟机所管理的内存中最大的一块

      存在的唯一目的:存放对象实例,几乎所有的对象实例在这里都有分配内存

    2. 方法区(共享

      存在的目的:存储已被虚拟机加载的类信息常量静态变量即时编译器编译后的代码等数据

    3. java栈(私有

      每个java方法被执行的时候都会创建一个栈帧(Stack Frame),用于存储局部变量、操作栈、动态链接、方法出口等信息。
      每个方法从被调用至执行完成的过程,就对应着一个栈帧在虚拟机从入栈到出栈的过程

    4. 本地方法栈(私有

      作用于 java栈类似,区别不过是:【java栈为虚拟机执行java方法服务】,【本地方法栈则是为虚拟机使用到的 Navtive方法服务】

    5. 程序计数器(私有

      存在的目的:当前线程执行的字节码的行号指示器


    jvm对象分配规则

    1. 对象优先分配在伊甸区(Eden),如果伊甸区没有足够的空间时,虚拟机执行一次 Minor GC

    2. 大对象(大对象:需要大量连续内存空间的对象。这里有个疑问:大量是多少?有没有标准?)直接进入老年代,这样做的目的是:避免在 伊甸区(Eden)和幸存者区(Survivor)之间发生大量的内存拷贝

    3. 虚拟机为每个对象定义了一个年龄计数器,如果对象经过了一次 Minor GC,那么对象会进入幸存者区,之后每经过一次 Minor GC,对象的年龄会+1。直到特定的年龄进入老年区

    4. 动态判断对象的年龄,如果幸存者区中,相同年龄(假设为x)的所有对象大小总和大于幸存者区的一半,那么所有年龄>=x的对象都将会直接进入老年代

    5. 空间分配担保,每次 Minor GC,jvm会计算从幸存者区移至老年区对象的平均大小,如果平均值大于老年区的内存空间剩余值大小,则进行一次 Full GC,如果小于则检查 HandlePromotionFailure 设置,并判断若设置为true,则进行 Minor GC,否则进行 Full GC



    三、垃圾回收

    对象存活判断

    判断对象是否存活一般有两种方式:

    1. 引用计数

      每个对象都有一个计数属性,新增一个引用时,计数+1;释放一个引用时,计数-1。

      计数=0 时就表明这个对象已经死了,此法不能解决对象互相循环引用问题

    2. 可达性分析

      从 GC Roots 开始向下搜索,搜索过的路径称为引用链,

      当一个对象没有任何引用链相连,则证明此对象已经死了,是不可达对象

    GC算法

    【待补充ing……】









    【以上内容是个人的学习总结,不慎之处欢迎评论斧正】

  • 相关阅读:
    M、V、VM分别代表什么?
    HTML行内元素、块状元素、行内块状元素的区别
    野指针与僵尸对象
    mybatis 引入java 常量
    mybatis 分页默认500条
    java 引用
    java 查看类大小
    java 排序多个条件
    java for循环批次处理
    Cause: java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String
  • 原文地址:https://www.cnblogs.com/wfg934dbk/p/14331818.html
Copyright © 2020-2023  润新知