Java JVM:内存、垃圾回收、并发锁机制

JVM 运行在操作系统上,与硬件没有直接的交互,是可运行 Java 代码的虚拟机

一、内存

在这里插入图片描述

  • 程序计数器 (线程私有)
    • 当前线程所执行的字节码的行号指示器,通过改变这个计数器的值来选取下一条需要执行的字节码指令
    • 每条线程都有一个独立的程序计数器,互不影响、独立存储,所以线程私有
    • 唯一一个没有规定任何OOM情况的区域
  • 虚拟机栈 (线程私有)
    • 生命周期与线程相同
    • 每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧,用于存储 局部变量表、操作数栈、动态连接、方法出口 等信息
      • 局部变量表放的是编译器可知的各种基本数据类型、对象引用类型
      • 局部变量表存储空间以局部变量槽来表示,64位的Long和Double类型占两个变量槽
    • 每个方法都被调用,直到执行完毕的过程,对应着一个栈帧在虚拟机栈中从入栈到出栈道过程
    • 线程申请的栈深度大于虚拟机所允许的深度:StackOverflowError异常
    • 允许动态扩展下,扩展到无法再扩展:OutOfMemoryError异常
  • 本地方法栈(线程私有)
    • 和虚拟机栈非常相似,虚拟机栈为虚拟机执行Java方法服务,本地方法栈是为虚拟机使用到本地(Native)方法服务
    • HotSpot虚拟机直接就把本地方法栈和虚拟机栈合二为一
  • (线程共享)
    • 虚拟机启动时创建,用于存放对象实例,所有的对象实例以及数组都应当在堆上分配 Java 堆是垃圾收集器管理的内存区域
    • Java堆可以实现固定大小,也可以扩展,主流的Java虚拟机都是按照可扩展来实现(参数-Xmx和-Xms设定)
  • 方法区(线程共享)
    • 存储已被虚拟机加载的类型信息、常量、静态变量、即使编译器编译后的代码缓存等数据
    • 运行时常量池
      • Class文件中有类的版本、字段、方法、接口等描述信息,还有一项常量池表
      • 用于存放编译器生成的各种字面量与符号引用,在类加载后存放到方法区的运行时常量池
      • 具备动态性
      • 常用String.intern()方法放入运行时常量池

二、垃圾回收

  • Java 堆从 GC 角度还可以细分为 新生代(Eden、From Servivor、To Servivor) 和老年代
    • 新生代:存放新 new 的对象,一般占据 1/3 堆内存,频繁创建对象就会频繁触发 MinorGC 进行垃圾回收
      • Eden:新对象出生地(如果很大的话,会直接分配到老年代),当 Eden 区内存不够的时候就会触发 MinorGC
      • From Survivor:上一次 GC 幸存者
      • To Survivor:保留了一次 MinorGC 过程中的幸存者
    • 老年代:主要存放应用程序中生命周期长的内存对象
      • 空间不够会触发 MajorGC,采用标记清除算法,老年代都不够的时候就会抛出 OOM 异常
  • MinorGC:采用复制算法(复制-清空-互换)
    • Eden、From Servivor 复制到 To Servivor,年龄 +1
      • 把前两区存活的对象复制到后者,如果有达到老年标准的或后者不够位置了,对象就会到老年代去,同时对象年龄 +1
    • 清空 Eden、From Servivor
    • To Servivor 和 From Servivor 互换
      • 原 To Servivor 成为下一次 GC 时的 From Servivor 区
  • Major GC:采用标记清除算法
    • 扫描老年代,标记出存活的对象,然后回收没有标记的对象
    • Major GC 耗时比较长,因为要扫描再回收,还会产生内存碎片
  • 永久代
    • 主要存放 Class 和 Meta 信息,Class 被加载的时候被放入永久区域,不会被 GC 清理,会随着加载的 Class 增多而膨胀,最后抛出 OOM
  • Java 8 与元数据
    • Java 8 中永久代已经被移除,元数据区取代了该功能,区别在于元空间不在虚拟机中,而是本地内存,由系统实际可用空间控制

三、并发锁机制

    • 乐观锁:CAS
    • 悲观锁:synchronized、vector、hashtable
    • 自旋锁:CAS
    • 可重入锁:synchronized、ReentrantLock、Lock
    • 读写锁:ReentrantReadWriteLock、CopyOnWriteArrayList、CopyOnWriteArraySet
    • 公平锁:ReentrantLock(true)
    • 非公平锁:synchronized、ReentrantLock(false)
    • 共享锁:ReentrantReadWriteLock 中读锁
    • 独占锁:synchronized、vector、hashtable、ReentrantReadWriteLock 中写锁
    • 重量级锁:synchronized
    • 轻量级锁:锁优化技术
    • 偏向锁:锁优化技术
    • 分段锁:concurrentHashMap
    • 互斥锁:synchronized
    • 同步锁:synchronized
    • 死锁:相互请求对方资源
    • 锁粗化:锁优化技术
    • 锁消除:锁优化技术
  • CAS 机制
    • 说明:无锁、自旋锁、乐观锁、轻量级锁,compareAndSet、compareAndSwap
    • 问题
      • 原子性问题:lock comxchgq 缓存行锁/总线锁
      • ABA 问题:可以添加一个版本号解决 AtomicStampedReference
      • 轻量级锁一定比重量级锁性能高吗?
  • 锁机制
    • 说明:互斥锁、悲观锁、同步锁、重量级锁
      • 线程阻塞、上下文切换、操作系统线程调度
  • static 下 sync 锁的是 class 对象,非 static 锁的是实例
  • 对象 OOP 组成
    • 对象头:MarkWord(Epoch、TreadID、age、偏向状态 0或1、锁状态标志)、MetaData、数组长度(数组才有)
    • 实例数据
    • 对齐填充位
  • 锁膨胀升级过程
    • 无状态
      • 默认延时 4s 开启偏向锁,可以通过 -XX:BiasedLockingStartupDelay=0 取消,如果不要偏向锁 -XX:-UserBiasedLocking = false
      • 偏向锁启用一个线程加锁,将线程 id 写入对象头 MarkWord,如果未启用直接升级轻量级锁
    • 偏向锁
      • 多个线程加锁升级为 CAS 轻度竞争
      • 调用 wait 方法 升级重量级锁(这个是重量级锁 monitor 锁才有的实现)
    • 轻量级锁
      • CAS 自旋不成功/锁膨胀 升级为重度竞争 自适应自旋(自旋 N 次之后拿不到锁就升级)
    • 重量级锁
  • LongAdder 分段 CAS 优化机制
    • 多个线程对同一个变量进行操作的时候,使用其他同类型变量进行接收,最后统一处理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值