JVM

synchronized锁

  • 用synchronize标记的代码编译为字节码后,会发现包含一个monitorenter和monitorexit指令,进入该方法是,会执行monitorenter,而在退出该方法时,不管是否正常退出,均需要进行monitorexit操作
  • monitorenter 和 monitorexit 操作所对应的锁对象是隐式的,每个锁对象拥有一个锁计数器和一个指向持有改锁的线程的指针;
  • 计数器为了可重入
  • 当执行monitorenter方法时,如果目标对象的锁计数器为0,JVM会将该锁对象持有的线程设置为当前线程,并将锁技术器 +1
  • 当目标锁对象的计数器不为0时,如果持有锁对象的线程是当前线程,JVM可以将锁对象的计数器+1,否则,需要等待其它线程释放锁对象
  • 重量级锁
    • 多个线程同时竞争同一把锁
    • 阻塞加锁失败的线程,当目标锁被释放时,唤醒线程。阻塞和唤醒需要依靠操作系统,涉及到系统调用,开销较大;可以用自旋解决,但需要权衡,即自适应自旋
    • 通过自适应自旋,避免线程在面对非常小的synchronized代码块时,仍被阻塞,唤醒的情况。
  • 轻量级锁
    • 多个线程不在同一时间段请求同一把锁,即没有锁竞争。JVM此时采用轻量级锁,避免重量级锁的阻塞和唤醒
    • 采用CAS操作,将锁对象的标记字段,替换为指针,指向当前线程栈上的一块空间,这里存储着原始锁对象的标记字段
  • 重量级锁和轻量级锁的区分
    • https://wiki.openjdk.java.net/display/HotSpot/Synchronization
    • 对象头中的标记字段,后两位用来标识锁的状态,00轻量级锁,01无锁(偏向锁),10重量级锁,11则跟垃圾回收算法的标记有关
    • 加锁先判断是否为重量级锁,如果不是,在栈空间划分一块空间,作为该锁的锁记录,并将锁对象的标记字段复制到该锁记录中;然后CAS替换锁对象的标记字段,如果当前锁对象的标记字段后两位是01,则替换为锁记录的地址,如果不是,1. 该线程重复获取同一把锁,将锁记录清零,表示该锁被重复获取;2.其它线程获取该锁,则将该锁膨胀为重量级锁,并阻塞当前线程。
    • 解锁先判断锁记录的值为0,代表重复进入同一把锁,直接返回。如果不是,CAS判断当前锁对象的标记字段是否为锁记录的地址值,如果是,替换为锁记录中的值,即锁对象原本的标记字段,此时改线程成功释放锁;如果不是,则意味这把锁已经膨胀为重量级锁,此时进入重量级锁的释放过程,释放因竞争该锁而被阻塞的线程。
  • 偏向锁
    • 只有一个线程请求某一把锁
    • 只在第一次请求时采用CAS操作,在锁对象的标记字段中记录下当前线程的地址,之后如果持有该偏向锁的线程的加锁操作将直接返回。
    • 加锁时,如果该对对象支持偏向锁,通过CAS操作,将该线程的地址记录在标记字段中,并将标记字段的后三位置为101,接下来,每当有线程请求这把锁时,判断锁对象标记字段后三位是否为101,是否包含当前线程的地址,以及偏向锁的年代数epoch是否相等。如果都满足,则当前线程持有该偏向锁,可以直接返回。
    • 撤销。请求加锁的线程和锁对象标记字段保持的线程地址不同时,需要等持有该偏向锁的线程到达安全点,并将偏向锁替换为轻量级锁。

对象存活分析

  • 引用计数法
    • 在对象头维护一个计数器,有其它地方引用该对象时,计数器+1,引用失效,计数器-1。当计数器不为0,判断该对象存活,否则为死亡
    • 无法解决循环引用,A,B的计数器都大于0
  • 可达性分析
    • 以一系列GC Roots的对象为起点,从这些起点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链想连时,则证明此对象是不可以用的
    • 判断对象不可用还不足以说明对象死亡,如果判断对象没有必要执行finalize()方法时,则判断对象死亡
    • 可作为GC Roots的对象
      • 虚拟机栈(栈帧中的本地变量表)中引用的对象
      • 方法区中静态变量引用的对象
      • 方法区中常量引用的对象
      • 本地方法栈中引用的对象

垃圾回收

  • 清除(swap)
    • 把死亡对象所占据的内存标记为空闲内存,并记录在一个空闲列表中,当需要新建对象时,内存管理模块会从该空闲列表中寻找空闲内存,并划分给新建的对象
    • 缺点:内存碎片;分配效率低,由于不连续,需要逐个访问列表中的项,来查找能够放入新建对象的空闲内存
  • 压缩
    • 把存活的对象聚集到内存区域的起始位置,从而留下一段连续的内存空间
  • 复制
    • 即把内存区域分为两等分,分别为from和to指针维护,用from指针指向的内存区域来分配内存。当发生垃圾回收时,把存活对象从from区域复制到to区域指向的内存中,并交换from指针和to指针。
  • 分代回收
    • Minor GC,当Eden区内存不够触发,Eden和from区存活对象复制到to区,然后交换from和to指针。如果对象被来回复制了15次以上,就晋升到老年代
    • 由于大部分对象的存活时间很短,因此新生代采用的是复制算法,只有少部分对象被复制,效率高
    • Full GC。 新生代的对象移动到老年代,但老年代的空间不足,容纳不下,就会触发。
    • 老年代对象生命周期长,大。没有额外空间担保,一般用清除或者整理算法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值