JVM基础知识简要概括

JVM初探

jvm体系结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RxnI0Mey-1583463998979)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200305170623614.png)]

  • 方法区:存储 static,final,Class,常量池。

  • 本地方法栈 :用来登记native 方法,最终的执行时,通过JNI加载本地方法库的方法(java本地接口)

  • java虚拟机栈 : 8大基本类型+对象引用+实例方法

    • 栈内存:主管程序的运行,声明周期和线程同步,线程结束栈内存释放,不存在垃圾回收问题

双亲委派机制

类加载器:

  1. BootstrapClassLoader (启动类加载器):负责加载jre/lib/rt.jar(c++编写,开发者无法直接获取启动类加载器的引用)
  2. ExtClassLoader(扩展类加载器) : 负责加载jre/lib/ext/*.jar(java编写)
  3. AppClassLoader(应用程序类加载器): 负责加载用户类路径(classpath)上指定的类库。(java编写)
  4. CustomClassLoader(用户自定义类加载器) : 加载指定路径的class文件(java编写)

工作流程:

  1. 当类加载器收到类加载的请求时,不断委派父加载器,直到启动类加载器
  2. 若启动类加载器能加载,则加载,不能的话,就抛出异常并通知子加载器加载
  3. 重复步骤二;

native

在95年创造java的时候,c和c++已经很流行了,java要占据一地,使Java也可以调用c,c++的程序,这就是native

native标记的 代表是非java编写的,会回去调用底层的c语言库,进入本地方法栈。

jvm在内存管理中开辟了一块标记区域:本地方法栈 用来登记native 方法,最终的执行时,通过JNI加载本地方法库的方法

new一个对象的过程

new一个对象分为,加载并初始化创建一个对象两个步骤,如果第一个步骤已经走过了,那么就会直接执行第二步;

如果没有则会进行类的加载和初始化:

  • 类的加载: 分为加载和连接两部分其中连接包括(验证,准备,解析)

    1. 加载: jvm找到对应的class文件,以二进制字节流的形式读取到jvm方法区中。
    2. 验证:总的来说就是检查是否符合java规范
      1. 是否符合Class文件规范
      2. 是否符合java语法(final标记的类是否有子类,final方法是否被重写等)
    3. 准备:为其静态变量分配空间并设置一个初始值,如果是静态常量则直接被赋值
    4. 解析:将符号引用转换为直接引用,和静态绑定(private,final,static 的方法与类和对象关联起来)
      • 符号引用 : java类并不知道所引用类的实际地址用符号引用代替
      • 直接引用 : 直接指向目标的指针
      • 静态绑定: 所有不会被重写的方法和域都会被静态绑定
  • 初始化的过程(先父后子)

    • 静态变量赋值 和 执行静态代码块
  • 创建对象

    • 在堆区为其分配空间(分配的内存包括本类和父类的所有实例变量,但不包括任何静态变量)
  • 对所有实例变量赋默认值 ( 将方法区内对实例变量的定义拷贝一份到堆区,然后赋默认值)

    • 执行实例初始化代码

      • 初始化顺序是先初始化父类再初始化子类,初始化时先执行实例代码块然后是构造方法
  • 在栈区定义引用变量,然后将堆区对象的地址赋值给它

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gLvQV1c0-1583463998980)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200306091811802.png)]

jdk1.8后,常量池,被分离出来,和元空间一起,逻辑上属于堆,物理上却不属于

VM调优参数 :-Xmx2048m -Xms1024m -XX:+PrintGCDetails(压制警告)

​ :-Xmx8m -Xms4m -Xlog:gc*(代替上面的gc参数)

-Xmx表示运行时最大可占用的内存(默认1/4)

-Xms程序启动时占用的内存(默认1/64)

默认经历15次GC没有被回收,进入养老区。

GC

GC主要是对堆和方法区进行的,程序计数器,虚拟机栈和本地方法栈都是线程私有的,随线程消失而消失不需要回收。

由上图知:堆中分为新生区和老年区

新生区: 伊甸园 :幸存区(to) : 幸存区(from) = 8 : 1: 1

  • 伊甸园 : 绝大部分刚创建的对象就存储在伊甸园区
  • 幸存一区 : 在伊甸园空间执行第一次GC(Minor GC)之后,存活的对象被移动到其中一个幸存者空间(Survivor)。每一次gc后存活的对象就会被移到同一个幸存区(to)
  • 幸存二区 : 当一个幸存者空间饱和,还在存活的对象会被移动到另一个幸存者(from)空间。然后会清空已经饱和的哪个幸存者空间。 清空的区就变成from区,from就变成了to区;
  • 在以上步骤中重复N次(N = MaxTenuringThreshold(年龄阀值设定,默认15))依然存活的对象,就会被移动到老年代
垃圾回收算法
  1. 标记清除法

    • 标记阶段 : 程序会检查每个对象是否为活动对象,如果是活动对象,则程序会在对象头部打上标记。
    • 清除阶段 : 对对象进行回收并取消标志位,并判断与前一个空闲分块是否连续,连续则合并。 (回收就是,将次分块连接到空闲链表中)
    • 分配 : 搜索空闲链表,找到大于或等于新对象size的块。

    不足:

    • 标记和清除过程效率都不高;
    • 会产生大量不连续的内存碎片,导致无法给大对象分配内存。
  2. 标记整理法

    • 让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

    优点 : 避免产生内存碎片

    不足 : 需要大量移动对象,效率低

  3. 复制法

    • 将内存分为两块,每次使用其中的一半,使用后若该对象存活则复制到另一半空间中,并释放刚刚使用的空间中的对象。

    不足: 内存只有一半了。

  4. 分代收集

    • 新生代使用:复制算法
    • 老年代使用:标记 - 清除 或者 标记 - 整理 算法

JMM(java内存模型)

什么是Volatile

Volatile是Java虚拟机 提供的 轻量级同步机制,是关键字。

  • 保证可见性
  • 不保证原子性
  • 禁止指令重排

什么是JMM

JMM: Java内存模型,不存在,概念,约定;

关于JMM的一些同步约定

  • 线程解锁前,必须把共享变量立刻写回。
  • 线程加锁前,必须读取主存中最新值到工作内存。
  • 加锁解锁是同一把锁。

内存交互操作有8种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类型的变量来说,load、store、read和write操作在某些平台上允许例外)

  • lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态

  • unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

  • read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用

  • load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中

  • use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令

  • assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中

  • store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用

  • write  (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中

JMM对这八种指令的使用,制定了如下规则:

  • 不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write
  • 不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存
  • 不允许一个线程将没有assign的数据从工作内存同步回主内存
  • 一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量实施use、store操作之前,必须经过assign和load操作
  • 一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解锁
  • 如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值
  • 如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量
  • 对一个变量进行unlock操作之前,必须把此变量同步回主内存
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值