你好offer之--JVM

本文详细探讨了Java虚拟机(JVM)的核心组件,包括类加载子系统、执行引擎、本地接口和运行时数据区。讲解了对象创建、内存异常、方法调用,重点剖析了垃圾回收算法(如分代收集和不同垃圾收集器)以及类加载的双亲委派模式。
摘要由CSDN通过智能技术生成

JVM

JVM核心

Java能够摆脱平台的原因就是Java源代码经过编译器变成字节码,字节码经过JVM解释成不同的机器码。而不同的操作系统有不同的JVM。

JVM包含两个组件和两个子系统

  • 类加载子系统:将class文件加载到运行时数据取
  • 执行引擎:由jit和垃圾回收器组成
  • 本地接口:与本地库进行交互
  • 运行时数据区:JVM的核心。包含方法区,程序计数器,堆,本地方法栈,虚拟机栈

运行时数据区

  • 程序计数器:当前线程所执行的字节码的行号指示器

  • Java虚拟机栈:会创建一个栈帧用于存储局部变量表、操作栈、动态链接、方法出口等信息。

  • 本地方法栈:主要区别是Java虚拟机栈执行的是Java方法服务,而本地方法栈执行Native方法服务

  • Java堆:垃圾回收的主战场,几乎所有的对象实例都是在这里分配的。Java堆又分为老年代(2/3,大对象直接进入老年代)和新生代(1/3)对象优先在 Eden 区分配。

  • 方法区:于存储类信息、常量、静态常量和即时编译后的代码等数据
    运行时常量池是方法区的一部分(用于存放编译期生成的各种字面常量和符号引用)

对象创建的过程:

  • 虚拟机遇到一条new指令时,先检查常量池是否已经加载相应的类,如果没有,必须先执行相应的类加载。
  • 类加载通过后,接下来分配内存。分配内存有两种,一种是指针碰撞另一种是空闲列表。
  • 因为对象的创建在虚拟机种并发执行的会有危险。可以采用CAS+失败重试或者每个线程在Java堆中预先分配一块内存

除了程序计数器外都有可能发生outofmemory

内存异常有两种情况,

  • 一种是内存泄漏:就是申请了内存,但是没有释放,导致内存空间浪费。通俗说法就是有人占着茅坑不拉屎。
  • 另一种是内存溢出:是申请内存时,JVM没有足够的内存空间。通俗说法就是去蹲坑发现坑位满了。

方法调用:

方法调用并不等同于方法执行,方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法),暂时还不涉及方法内部的具体运行过程。

JVM垃圾回收

判断对象是否存活:

  • 引用计数法:有一个bug就是循环引用
  • 可达性分析:从根节点向下延申,对象没有被引用,则判断有无finall关键字,无则直接回收有则进行标记,标记两次后进行回收

垃圾回收算法

  • 标记清除:效率高但是有碎片化空间

  • 标记复制:可有空间变少但是可用内存变小了

  • 标记整理:结合的折中方法,将存活对象放在一端

  • 分代收集:新生代用复制,老年代用清除或者整理。永久代基本不清理

Minor GC新生代、Major GC老年代

由于Full GC需要对整个堆进行回收,所以比Minor GC要慢,因此应该尽可能减少Full GC的次数。它的收集频率较低,耗时较长。

垃圾收集器

  • 新生代:Serial、PraNew、Parallel Scavenge(动态调节及及进行高吞吐量,高效利用 CPU)
  • 老年代:Serial Old、Parallel Old、CMS(尽可能少的减少停顿时间,有碎片)
  • 最强的G1(后台维护一个 优先列表):整体上是标记整理,局部是复制

JVM的类加载

类被编译成字节码文件(具有语言无关性)加载到JVM,并对数据进行验证,准备,解析,初始化后,最终形成可以被虚拟机直接使用的Java类型就是类加载机制。准备,解析,初始化都是在程序运行期间完成的。这种策略虽然会增加一些额外的开销,但是增加了灵活性。

类加载的七个过程:

  • 加载:获取此类的字节码、静态存储结构转化为方法区的运行时数据结构、生成对象
  • 验证:文件格式验证,字节码验证,符号引用验证
  • 准备:为类变量分配内存(被 static 修饰的变量)并设置类变量初始值(数据类型的零值)的阶段。这些变量所使用的内存都将在方法区进行分配
  • 解析:将常量池内的符号引用(一组符号来描述所引用的目标,符号可以上任何形式的字面量,只要使用时能无歧义地定位到目标即可。)替换为直接引用(直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄)的过程
  • 初始化:执行类中定义的 Java 程序代码。初始阶段是执行类构造器 () 方法的过程。
    使用
    卸载

类加载器:

  • 启动类加载器(c++):加载Java的核心类库
  • 扩展类加载器:加载Java的扩展类库
  • 应用程序类加载器:Java应用的类一般都是在这加载的
  • 用户自定义加载器:用户自己定义的加载器,继承自ClassLoader

双亲委派模式:

当一个类加载器收到一个类加载请求的时候,他首先不会自己先去加载,而是交给父类加载,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个类加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。双亲委派模式主要是保证加载的唯一性,防止类重名而造成的歧义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值