JVM 笔记

1.JVM运行时内存分布

1.1 虚拟机栈

存储局部变量表、操作数、动态连接、方法出口等。

1.2 堆

存放所有对象实例,所有线程共享。垃圾收集器主要管理区域。

1.3 方法区

存储类型信息,常量、静态变量、即时编译器编译的代码缓存等。

2. 垃圾收集器

引用计数?NO,并不是主流。 可达性分析?Yes

2.1 分代收集

  • 标记清除
    标记被引用的,清除未使用的。或反过来。
    缺点:执行效率不稳定;内存空间碎片化
  • 标记复制
    内存均分2块,使用完后把存活对象复制到另一块,清空当前块。
    缺点:内存浪费严重
  • 标记整理
    标记存活,然后将存活对象向内存一端移动保持内存紧凑。
    缺点:内存移动过程中需要暂停用户应用,造成处理延迟。

2.2 垃圾收集器对比

常见的垃圾收集器分3类,未列举JDK8以后的新收集器

  • 负责堆年轻代中的内存回收
    包括:Serial,ParNew,Parallel Scavenge
  • 负责堆老年代中的内存回收
    包括:Serial Old,CMS,Parallel Old
  • 负责整个Java堆中的内存回收(新生代和老年代)
    包括:G1

2.3 垃圾收集参数调优

各种垃圾收集器都有各自的优缺点,需要根据业务出发,进行基于垃圾回收器的性能测试,然后选择适合的。

-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParallelGC :新生代使用并行回收收集器,更加关注吞吐量
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:设置用于垃圾回收的线程数
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:设定CMS的线程数量
-XX:+UseG1GC:启用G1垃圾回收器

3. Class文件

JVM不仅仅只是Java语言,因此使用Class文件作为编译产出物。格式如下:

4. 加载

4.1 类的生命周期

4.2 类加载器

定义:通过一个类的全限定名来获取描述该类的二进制字节流
作用:将类加载到JVM
-启动类加载器
负责<JAVA_HOME>lib目录下的类
-扩展类加载器
负责<JAVA_HOME>libext下的类
-应用程序类加载器
负责用户路径下所有类的加载

4.3 执行引擎

分派:静态分派和动态分派

1.静态类型

编译期可知,不会根据运行条件产生类型变化。如 Object o1 = new String()

2.实际类型

编译期不可知,根据运行结果产生变化。 如 Object o2 = isTrue?new String():new Int()

3.静态分派(overload)

依赖静态类型决定方法执行版本的分派动称为静态分派,因此静态分派不是由虚拟机执行,而是在编译期确定的。最广泛的的情景就是重载
注意:静态分派在拥有多个可适配重载版本的时候,会存在潜在的类型转换。

4. 动态分派(override)

在运行期进行接收者的实际类型确定,在操作数栈顶中查找对象的实际类型并判断相符。如果不符则向父类搜索和验证。这就是重写的确定过程。

5. 编译与执行

5.1 编译器分类:

-前端编译器
.java文件到.class文件
-即时编译器
字节码到机器码
-提前编译器
.java到机器码

5.2 javac编译器

属于前端编译器,包括4个过程:

  • 准备过程
    初始化插入式注解器
  • 解析与填充过程
    词法分析、语法分析、填充符号表
  • 插入式注解器注解过程
    以@注解形式的代码解析发生在这里
  • 分析与字节码生成过程
    数据流和控制流分析、自动拆装箱,解语法糖等

经过这4个过程产生字节码。

6 线程于安全

java多线程的内存模型

主内存与工作内存间存在同步的问题。

6.1 volatile关键字

保证变量对所有线程可见性;禁止指令重排优化
注意:对线程的可见性并不一定保证线程安全,只及时回写主内存,但其他线程如果变量本身计算基于该变量的值,则保证不了安全。

6.2 线程实现

1:1线程全映射内核线程
1:N一个内核线程映射所有用户线程,线程同步不由系统管理
N:M多内核线程映射所有用户线程,线程同步不由系统管理

Java的HotSpot使用1:1映射,抢占式多线程实现。

6.3 synchronized关键字

以互斥同步手段实现线程安全,在同步块前后形成monitorenter和monitorexit字节码。在进出时获取对象锁。
注意:由于java的线程是基于系统,那么在获取锁的时候唤醒其他线程会切换用户态和核心态,频繁切换会造成性能浪费。

6.4 Lock接口

在sync关键字基础上,增加了高级功能:等待可中断、公平锁、锁绑定多个条件

6.5 非阻塞同步

CAS:Compare-and-Swap
依赖于新的处理器指令,比较并交换,JDK9以后可用。

原文地址:https://www.cnblogs.com/full-stack-engineer/p/13699947.html