深入java虚拟机(极简版读书笔记)(二)

简介: hotspot内置两个编译器C1和C2,解释器和编译器搭配使用的方式在虚拟机中称为“混合模式”(Mixed Mode) c1编译器获取更快的编译速度,c2获取更高的编译质量。

接上文:深入java虚拟机(极简版读书笔记)(一)


六  虚拟机字节码执行引擎


    栈帧的概念结构


50.jpg


局部变量表

      第0位索引存储的是所属对象实例的引用 ,即this


七  晚期(运行期)优化


  • hotspot内置两个编译器C1和C2,解释器和编译器搭配使用的方式在虚拟机中称为“混合模式”(Mixed Mode) c1编译器获取更快的编译速度,c2获取更高的编译质量。
  • 在虚拟机执行架构中,解释器与编译器经常配合工作。
  • 参数 -Xint 强制虚拟机为解释模式(Interpreted mode),这时编译器完全不介入
  • 参数 -Xcomp强制为解释模式(Compiled Mode)
  • 分层编译策略 JDK7默认开启
  • 栈上替换(On Stack Replacement --OSR),即方法栈帧还在栈上,方法就被替换了
  • 判断一段代码是不是热点代码称为热点探测
     • 基于采样的热点探测
     • 基于计数器的热点探测--目前用的是这种


 

7.1 JIT编译器、解释、编译


       在 JVM 中,编译是基于两个计数器的:一个是方法被调用的次数,另一个是方法中循环被回弹执行的次数。


60.jpg


八 内存模型


8.1 volatile


  • volatile可以禁止指令重排序优化
  • 保证可见性、不保证原子性
  • 不保证原子性,并不保证互斥(也就是说多个线程并发修改某个变量时,依旧会产生多线程问题,但适合使用一个线程写,多个线程读的场合)
  • 禁止指令重排的原理是插入许多内存屏障指令


   以下场景可以使用volatile

  • 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值
  • 变量不需要与其他的状态变量共同参与不变约束


8.2 volatile 原理


       使用Violatile修饰的变量在汇编阶段,会多出一条lock前缀指令,它在多核处理器下会引发两件事情:将当前处理器缓存行的数据写回到系统内存 这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效。通常处理器和内存之间都有几级缓存来提高处理速度,处理器先将内存中的数据读取到内部缓存后再进行操作,但是对于缓存写会内存的时机则无法得知,因此在一个处理器里修改的变量值,不一定能及时写会缓存,这种变量修改对其他处理器变得“不可见”了。但是,使用Volatile修饰的变量,在写操作的时候,会强制将这个变量所在缓存行的数据写回到内存中,但即使写回到内存,其他处理器也有可能使用内部的缓存数据,从而导致变量不一致,所以,在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期,如果过期,就会将该缓存行设置成无效状态,下次要使用就会重新从内存中读取。


       volatile语义中的内存屏障策略非常严格保守,非常悲观且毫无安全感的心态:在每个volatile写操作前插入StoreStore屏障,在写操作后插入StoreLoad屏障;在每个volatile读操作前插入LoadLoad屏障,在读操作后插入LoadStore屏障;由于内存屏障的作用,避免了volatile变量和其它指令重排序、线程之间实现了通信,使得volatile表现出了锁的特性。


8.3    原子性、可见性、 有序性


  • 基本数据类型的读写是具有原子性的 在synchronized块之间的操作也具备原子性
  • volatile变量保证了多线程操作时变量的可见性,而普通变量则不能保证这一点。
  • synchronized和final也可以实现可见性
  • volatile和synchronized保证线程间操作的有序性


8.4  先行发生原则 happens-before


  • 程序次序规则。在一个线程内,书写在前面的代码先行发生于后面的。确切地说应该是,按照程序的控制流顺序,因为存在一些分支结构。 
  • Volatile变量规则。对一个volatile修饰的变量,对他的写操作先行发生于读操作。
  • 线程启动规则。Thread对象的start()方法先行发生于此线程的每一个动作。
  • 线程终止规则。线程的所有操作都先行发生于对此线程的终止检测。
  • 线程中断规则。对线程interrupt()方法的调用先行发生于被中断线程的代码所检测到的中断事件。
  • 对象终止规则。一个对象的初始化完成(构造函数之行结束)先行发生于发的finilize()方法的开始。
  • 传递性。A先行发生B,B先行发生C,那么,A先行发生C。
  • 管程锁定规则。一个unlock操作先行发生于后面对同一个锁的lock操作。


  时间先后顺序与先行发生原则之间基本没有太大的关系。

 

     

九 锁


9.1 锁优化


9.1.1 自旋锁


      自旋锁原理非常简单,如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。但是线程自旋是需要消耗cup的,说白了就是让cup在做无用功,线程不能一直占用cup自旋做无用功,所以需要设定一个自旋等待的最大时间。如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,就会导致其它争用锁的线程在最大等待时间内还是获取不到锁,这时争用线程会停止自旋进入阻塞状态。


9.1.2 轻量级锁


62.jpg


63.jpg


9.1.3 偏向锁


       偏向锁也是JDK 6中引入的一项锁优化措施,它的目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。如果说轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,那偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS操作都不去做了。偏向锁中的“偏”,就是偏心的“偏”、偏袒的“偏”。它的意思是这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁一直没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。


65.jpg


66.jpg


9.2 CAS


     CAS(Compare and Swap)是一种乐观锁(每次不加锁,假设没有冲突去完成某项操作,如果因为冲突失败就重试,直到成功为止。)


  • CAS存在ABA问题, java用 AtomicStampedReference,带有标记的原子引用类解决了这个问题。
  • AtomicInteger就是用CAS实现的

AtomicLongFieldUpdater可以对指定"类的 'volatile long'类型的成员"进行原子更新。它是基于反射原理实现的。

  • 只能保证一个共享变量的原子操作。对一个共享变量执行操作时,CAS能够保证原子操作,但是对多个共享变量操作时,CAS是无法保证操作的原子性的。Java从1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个对象里来进行CAS操作。
  • CAS通过调用JNI的代码实现的。JNI:Java Native Interface为JAVA本地调用,允许java调用其他语言。而compareAndSwapInt就是借助C来调用CPU底层指令(Atomic::cmpxchg(x,addr,e))实现的。





相关文章
|
存储 算法 安全
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
196 0
|
11月前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
存储 算法 Java
Java虚拟机(JVM)的内存管理与性能优化
本文深入探讨了Java虚拟机(JVM)的内存管理机制,包括堆、栈、方法区等关键区域的功能与作用。通过分析垃圾回收算法和调优策略,旨在帮助开发者理解如何有效提升Java应用的性能。文章采用通俗易懂的语言,结合具体实例,使读者能够轻松掌握复杂的内存管理概念,并应用于实际开发中。
|
Java
Java常见JVM虚拟机指令(47个)
Java常见JVM虚拟机指令(47个)
159 3
Java常见JVM虚拟机指令(47个)
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
302 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
存储 监控 算法
探索Java虚拟机:深入理解JVM内存模型和垃圾回收机制
在Java的世界中,JVM是核心所在,它不仅承载着代码的运行,还管理着内存资源。本文将带你深入了解JVM的内存模型和垃圾回收机制,通过具体数据与案例分析,揭示它们对Java应用性能的影响,并探讨如何优化JVM配置以提升效率。
319 27
|
监控 Oracle Java
(一)JVM成神路之初识虚拟机 - 探寻Java虚拟机的前世今生之秘
JVM(Java Virtual Machine)Java虚拟机的概念大家都不陌生,Java之所以可以做到“一次编译,到处运行”的跨平台性,其根本原因就在于JVM。JVM是建立在操作系统(OS)之上的,Java虚拟机屏蔽了开发人员与操作系统的直接接触,我们在通过Java编写程序时,只需要负责编写Java代码即可,关于具体的执行则会由JVM加载字节码后翻译成机械指令交给OS执行。
362 1
|
存储 Ubuntu Java
【Linux】已解决:Ubuntu虚拟机安装Java/JDK
【Linux】已解决:Ubuntu虚拟机安装Java/JDK
811 1
|
Java 数据安全/隐私保护 Windows
【Azure Developer】使用Java代码启动Azure VM(虚拟机)
【Azure Developer】使用Java代码启动Azure VM(虚拟机)
111 0
|
存储 Java API
【Azure Developer】通过Azure提供的Azue Java JDK 查询虚拟机的CPU使用率和内存使用率
【Azure Developer】通过Azure提供的Azue Java JDK 查询虚拟机的CPU使用率和内存使用率
145 0
下一篇
开通oss服务