博客
关于我
一文带你学会java的jvm精华知识点
阅读量:428 次
发布时间:2019-03-06

本文共 4933 字,大约阅读时间需要 16 分钟。

JVM类实例化顺序及类加载机制

前言

本文通过20多个问题,深入探讨JVM的核心机制,帮助理解JVM的运行原理和优化方法。


1. Java类实例化顺序

正确顺序如下:

  • 父类静态代码块
  • 父类静态变量
  • 子类静态代码块
  • 子类静态变量
  • 父类成员变量赋值
  • 父类构造方式开始执行
  • 子类成员变量赋值
  • 子类构造方式开始执行
  • 注意事项:

    • 静态变量和静态代码块的顺序是明确的,静态代码块始终在静态变量之前执行。
    • 静态代码块和静态变量的初始化顺序需遵循上述顺序。

    示例分析:

    public class ClassLoaderTest {    public static void main(String[] args) {        sons sons = new sons();    }}class parent {    private static int a = 1;    private static int b;    static {        b = 1;        System.out.println("1.父类静态代码块:赋值b成功");        System.out.println("1.父类静态代码块:a的值" + a);    }    int initc() {        System.out.println("3.父类成员变量赋值:----> c的值" + c);        this.c = 12;        return c;    }    parent() {        System.out.println("4.父类构造方式开始执行----> a:1, b:1");        System.out.println("4.父类构造方式开始执行----> c:12");    }}class son extends parent {    private static int sa = 1;    private static int sb;    static {        sb = 1;        System.out.println("2.子类静态代码块:赋值sb成功");        System.out.println("2.子类静态代码块:sa的值" + sa);    }    int initc2() {        System.out.println("5.子类成员变量赋值---->:sc的值" + sc);        this.sc = 12;        return sc;    }    son() {        System.out.println("6.子类构造方式开始执行----> sa:1, sb:1");        System.out.println("6.子类构造方式开始执行----> sc:12");    }}

    执行结果:

  • 父类静态代码块:赋值b成功
  • 父类静态代码块:a的值1
  • 子类静态代码块:赋值sb成功
  • 子类静态代码块:sa的值1
  • 父类成员变量赋值:----> c的值0
  • 父类成员变量赋值:----> c的值12
  • 父类构造方式开始执行----> a:1, b:1
  • 父类构造方式开始执行----> c:12
  • 子类成员变量赋值---->:sc的值0
  • 子类构造方式开始执行----> sa:1, sb:1
  • 子类构造方式开始执行----> sc:12

  • 2. JVM虚拟机何时结束生命周期?

    • 执行了 System.exit() 方法;
    • 程序正常执行结束;
    • 程序在执行过程中遇到了异常或错误而异常终止;
    • 由于操作系统出现错误导致Java虚拟机进程终止。

    3. JVM类加载机制

    类加载机制分为三个阶段:

  • 加载阶段:

    • 将类的 .class 文件中的二进制数据加载到内存中,放入方法区。
    • 创建 Class 对象,封装类在方法区的数据。
  • 连接阶段:

    • 包含三个小阶段:
      • 验证阶段: 检查类文件的结构和语义,确保类的兼容性。
      • 准备阶段: 给类和成员变量分配内存,设置初始值。
      • 解析阶段: 将符号引用替换为直接引用。
  • 初始化阶段:

    • 对类的静态变量和成员变量进行赋值。
    • 初始化类的构造方式。

  • 4. Java类的初始化时机

    主动使用:

  • 创建类实例
  • 访问静态变量或进行静态变量赋值
  • 调用静态方法
  • 反射
  • 初始化子类
  • Java启动类(具有 main 方法)
  • 被动使用:

  • 通过子类引用父类静态字段(不会初始化子类)
  • 通过数组引用类(不会触发类的初始化)

  • 5. Java类加载器

    三大内置类加载器:

  • 根类加载器(Bootstrap ClassLoader):

    • 负责加载 java.lang.* 类。
    • 加载路径由 sun.boot.class.path 指定。
  • 扩展类加载器(Ext ClassLoader):

    • 负责加载 javahome/jre/lib/ext 目录下的 .jar 文件。
  • 系统类加载器(System ClassLoader):

    • classpath 加载类。
    • 可通过 -Djava.class.path 指定加载路径。
  • 用户自定义类加载器:

    • 继承 ClassLoader 类,实现 findClass 方法。
    • 通过二进制流读取类文件,调用 defineClass 定义类。

    6. 自定义类加载器实现

    public class MyClassLoader extends ClassLoader {    public MyClassLoader(String fileName) {        super(fileName);    }    @Override    protected Class
    findClass(String className) throws ClassNotFoundException { // 通过二进制流加载类文件 byte[] classData = getClassData(className); return defineClass(className, classData, 0, classData.length); }}

    7. Java类的双亲委派机制

    双亲委派流程:

  • 当一个类加载器请求加载某类时,先询问其父类加载器是否已经加载该类。
  • 如果父类加载器未加载该类,请求父类加载器加载。
  • 如果父类加载器无法加载,才由当前类加载器自己加载。
  • 优点:

    • 提高安全性,防止恶意代码替代。
    • 确保类的唯一性和一致性。

    8. JVM破坏双亲委派机制

    public class MyClassLoader extends ClassLoader {    @Override    public Class
    loadClass(String className) throws ClassNotFoundException { System.out.println("自己加载:" + className); return super.loadClass(className); }}

    9. JVM类的命名空间

    命名空间由类加载器及其父类加载器构成。

    • 不同命名空间可以有相同的类全名。
    • 使用同一类加载器加载相同类,返回的 Class 对象相同。

    10. JVM运行时包

    运行时包由类加载器的命名空间和类全限定名称确定。

    • 保证了不同类加载器加载的类互不干扰。
    • 避免了恶意代码伪造核心库类。

    11. JVM类加载器缓存机制

    类加载器维护一个类列表,记录已加载的类。

    • 加载类时,先在类列表中查找。
    • 如果未加载,进行加载和缓存。

    12. JVM类卸载

    卸载条件:

  • 类的所有实例已被 GC。
  • 类加载器实例已被回收。
  • 类实例在其他地方无引用。

  • 13. Java是解释语言还是编译语言?

    Java是解释语言。

    • 虚拟机解释 .class 文件为字节码执行。
    • 编译后一次编译,处处运行,支持跨平台。

    14. JVM内存区域

    内存区域包括:

  • 程序计数器(Program Counter)
  • 虚拟机栈(VM Stack)
  • 本地方法栈(Native Method Stack)
  • 堆内存(Heap)
  • 方法区(Method Area,永久代)

  • 15. JVM直接内存

    直接内存(Direct Memory)

    • NIO 类提供,基于通道和缓冲区分配内存。
    • 不受 Java 堆大小限制。
    • 适用于频繁访问大内存的场景。

    16. JVM堆内部结构

    堆结构:

  • 新生代(Nepheap):

    • Eden 区(新对象出生地)
    • Survivor 区(存活对象区)
    • 默认比例:8:1:1(Eden: SurvivorFrom: SurvivorTo)
  • 老年代(Tenured Generation):

    • 存存活期长的对象。
    • 使用标记-清除或标记-整理算法。

  • 17. 为什么移除永久代?

    永久代的问题:

  • 字符串存放在永久代,可能引发性能问题。
  • 永久代大小难以确定。
  • 垃圾回收复杂度高。
  • Oracle HotSpot 不再使用永久代。

  • 18. JVM触发 Full GC 的几种情况

  • System.gc() 调用(建议性触发)
  • 老年代空间不足
  • 永生区空间不足
  • CMS GC 时出现 promotion failedconcurrent mode failure
  • 新生代中分配很大对象

  • 19. JVM判断对象是否可回收

    可达性分析:

    • 从 GC Roots 出发,标记所有可达对象。
    • 不可达对象需两次标记后方可回收。

    20. JVM垃圾回收算法

    常见垃圾回收算法:

  • 标记-清除算法:

    • 标记阶段:标记可达对象。
    • 清除阶段:清除不可达对象。
  • 标记-整理算法:

    • 标记阶段:标记可达对象。
    • 整理阶段:移动存活对象到一侧,清理另一侧。
  • 复制算法:

    • 将堆分为两半,复制存活对象到另一侧,清理旧堆空间。
  • 分代收集算法:

    • 根据对象存活周期分为新生代和老年代,分别采用不同算法。

  • 21. Java引用类型

    引用类型:

  • 强引用:

    • 使用 new 关键字创建,无法被 GC 回收。
  • 软引用:

    • 使用 SoftReference,内存不足时回收。
  • 弱引用:

    • 使用 WeakReference,内存不足时直接回收。
  • 虚引用:

    • 使用 WeakReference 并关联引用队列。

  • 22. JVM垃圾收集器

    常见垃圾收集器:

  • Serial垃圾收集器:

    • 单线程,复制算法。
  • ParNew垃圾收集器:

    • 多线程,复制算法。
  • Parallel Scavenge垃圾收集器:

    • 多线程,复制算法,优化吞吐量。
  • Serial Old垃圾收集器:

    • 单线程,标记-整理算法。
  • Parallel Old垃圾收集器:

    • 多线程,标记-整理算法。
  • CMS垃圾收集器:

    • 多线程,标记-清除算法,优化垃圾回收停顿时间。
  • G1垃圾收集器:

    • 基于标记-整理算法,支持低停顿垃圾回收。

  • 23. JDK7、8、9默认垃圾回收器

    • JDK7、8: Parallel Scavenge(新生代)+ Parallel Old(老年代)
    • JDK9: G1垃圾收集器

    24. JDK命令行工具

  • jhat: 堆转储快照分析工具。
  • jstack: 堆栈跟踪工具。
  • JConsole: Java监视与管理控制台。

  • 25. JVM调优配置

    常用调优参数:

    • -XX:NewGenSize:新生代大小。
    • -XX:TenuredGenerationSize:老年代大小。
    • -XX:MaxPermSize:永久代大小(已废弃)。
    • -XX:MetaspaceSize:元数据区大小。

    26. OSGi

    OSGi(Open Service Gateway Initiative):

    • 动态化模块化系统。
    • 服务发现和动态更新。
    • 模块级热部署,提升系统灵活性。

    以上是JVM核心知识点的详细解答,涵盖了类实例化顺序、类加载机制、垃圾回收算法等多个方面。

    转载地址:http://xguyz.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现翻转图像augmentation算法(附完整源码)
    查看>>
    Objective-C实现莱布尼兹级数求解π的近似值(附完整源码)
    查看>>
    Objective-C实现获取 Collatz 序列长度算法(附完整源码)
    查看>>
    Objective-C实现获取CPU温度(附完整源码)
    查看>>
    Objective-C实现获取GPU显卡信息(附完整源码)
    查看>>
    Objective-C实现获取HID设备列表 (附完整源码)
    查看>>
    Objective-C实现获取文件头的50个字符(附完整源码)
    查看>>
    Objective-C实现获取本机ip及mac地址(附完整源码)
    查看>>
    Objective-C实现获取本机系统版本(附完整源码)
    查看>>
    Objective-C实现重载[ ](附完整源码)
    查看>>
    Objective-C实现随机图生成器算法(附完整源码)
    查看>>
    Objective-C实现高斯消元法(附完整源码)
    查看>>
    Objective-C语法之代码块(block)的使用
    查看>>
    Objenesis创建类的实例
    查看>>
    OC Xcode快捷键
    查看>>
    OC 内存管理黄金法则
    查看>>
    OfficeWeb365 SaveDraw 文件上传漏洞复现
    查看>>
    office中的所有content type
    查看>>
    office之Excel 你会用 Ctrl + E 吗?
    查看>>
    OGG初始化之使用数据库实用程序加载数据
    查看>>