• 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以后可用。

  • 相关阅读:
    Jenkins历史构建作业jobs的删除与管理
    Redis消息队列与主流的消息队列中间件对比
    GDAL数据模型
    Android的语言切换
    GDAL驱动实现向导
    Win7 安装IIS
    局域网中其他机器不能访问本机IIS网站
    DXF库(dxflib)使用指南
    GDAL中文学习资料
    QT的中文站址
  • 原文地址:https://www.cnblogs.com/full-stack-engineer/p/13699947.html
Copyright © 2020-2023  润新知