面试题|Java|JVM

2020-07-12  本文已影响0人  萌新CAT

Jvm数据区

[图片上传失败...(image-cd876b-1594521117849)]

堆的分类

首先分配内存到Eden区,当发生Gc之后转移到s0或者s1中(如果s0先被使用,那么下一次则使用s1,总之是为了保留新生代的内容),每一次gc都会给新生代数据记录次数,一般来说超过15次则进入老年代

运行常量池

Java对象的创建过程

  1. 类加载
  2. 分配内存
  3. 初始化零值
  4. 设置对象头
  5. 执行init

类加载过程

类加载过程图
  1. 加载 (所需类的加载过程)

    • 通过类的全限定名获取该类的二进制流(通过class全限定名从本地,网络,专有数据库中的jar或者zip中获取.class文件)
    • 生成java.lang.class对象作为方法区进入该对象的入口
    • 将字节流的存储结构转化到jvm方法区中运行时的数据结构
  2. 验证 (了解Class字节文件是否符合当前虚拟机要求)

    • 文件格式验证: 字节流是否符合class文件规范
    • 元数据验证: 是否符合java的语法规范,例如继承接口,是否实现了接口中的方法
    • 字节码验证: 数据和控制流验证,保证方法中的类型转换有效
    • 符号引用验证: 验证是否可以通过符号引用找到相应的对象和变量
  3. 准备 (为类的变量分配内存和设置类的初始值(即方法区分配这些变量空间))

    • 为变量分配空间
    • 为变量初始化赋值的过程,例如int 赋值为 0 ,对象赋值为 null 等
    • 特殊 private static final a = 1
      正常来说,应该是初始化阶段赋值,但是这个情况下直接在方法去中替换a = 1 ,则在准备阶段就完成赋值
  4. 解析 (虚拟机将常量池中的符号引用转为直接引用的过程)

    • 什么是符号引用?
      用一串不会有歧义的符号来标识引用的对象或者是变量
    • 什么是直接引用?
      正式用指针去引用符号和变量
  5. 初始化

真正按照程序员的意愿去初始化值

分配内存

分配方法
  1. 指针碰撞
    内存空间比较整洁,直接移动指针分配空间
  2. 空闲链表
    “见缝插针”,空间不连续,则找到空闲的地方插入数据
线程安全问题
  1. 利用CAS不都安的尝试获取内存空间直到成功(目前虚拟机的解决方案)
  2. TLAB: 为每个线程独自分配一部分空间,且独有,分配的时候优先分配到该空间中

设置对象头

例如Synchronized关键字需要Mark Word中的monitor对象(MonitorExit,MonitorEnter)

对象的访问方式

  1. 句柄访问


    image

    reference -> 句柄池中指针 -> 实例数据

  2. 直接访问


    image

    reference -> 实例数据

  3. 句柄和直接访问的优缺点分析

论访问速度直接访问最快,但是如果需要删除的话需要直接删除数据
句柄中则可以直接把句柄值赋null,效率更快

对象死亡的分析方法

  1. 程序计数法 : 清零以后则可以判断死亡
  2. 可达性分析法 : 以Gc root为起点 看看各个对象是否可以连接起来,如果连接不起来,被独立则可以判断回收

引用的类型

垃圾回收算法

垃圾回收器

单线程回收垃圾,回收的时候需要暂停其它的一切线程

对Serial的升级,其它不变,就是变成多线程

提升吞吐量(程序运行时间/CPU使用时间),提高回收次数,减少回收时间

双清委派模型

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。
而有了双亲委派模型,黑客自定义的java.lang.String类永远都不会被加载进内存。因为首先是最顶端的类加载器加载系统的java.lang.String类,最终自定义的类加载器无法加载java.lang.String类

双亲委派模型的破坏 (借鉴CSDN博主的文章说的很完整了)

原生的JDBC中Driver驱动本身只是一个接口,并没有具体的实现,具体的实现是由不同数据库类型去实现的。例如,MySQL的mysql-connector-.jar中的Driver类具体实现的。 原生的JDBC中的类是放在rt.jar包的,是由启动类加载器进行类加载的,在JDBC中的Driver类中需要动态去加载不同数据库类型的Driver类,而mysql-connector-.jar中的Driver类是用户自己写的代码,那启动类加载器肯定是不能进行加载的,既然是自己编写的代码,那就需要由应用程序启动类去进行类加载。于是乎,这个时候就引入线程上下文件类加载器(Thread Context ClassLoader)。有了这个东西之后,程序就可以把原本需要由启动类加载器进行加载的类,由应用程序类加载器去进行加载了。
————————————————
版权声明:本文为CSDN博主「Jack老师」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/luoyang_java/article/details/92598142

参考文章

上一篇 下一篇

猜你喜欢

热点阅读