《hotspot实战》重点笔记

  1. 常量池中持有Class文件中引用的虽有字符串常量、类名、接口名、字段名等所有符号信息。
  2. 类的加载过程从class文件中读取字节流,并按照虚拟机对class文件的规范解析出类或者接口,并创建相应的类或者接口。
  3. 链接是让虚拟机运行时识别有效的类或者接口类型的过程,分为验证,准备和解析三个阶段;验证是确保class文件是按照规范的格式的。准备环节为类或者接口的静态字段分配空间并默认值初始化。解析环节是将符号引用转换为直接引用。
  4. 解析的主要目标是将常量池中的类、接口、字段、类方法或者接口方法这4类符号引用(常量池中的字符串表示)转换为直接引用,即运行时的实际内存地址。
  5. 创建对象时,虚拟机从栈顶去的目标对象的在常量池中的索引,接着通过索引定位到目标对象的类型。接下来,虚拟机根据该类的状态来采取相应的分配方案,在内存中分配实例空间,并完成实例数据和对象头的初始化。
  6. 对象的创建过程会根据该类是否已经被加载和正确解析可以分为快速分配和满速分配。快速分配是指实例在分配之前已经完成了类的解析,所以只要在内存中分配空间就行,此时又分两种,可以分配到线程私有区域或者共享堆;因为hotspot通过TLABs技术,可以将对象分配在线程私有区域,分配时首先尝试在TLABs中分配,因为线程私有,所以不用加锁,速度很快,如果分配失败了,则在共享堆的新生代的Eden区中分配。
  7. 栈和PC都是线程私有的,是线程执行程序的工作场所。每一个线程都关联着唯一的栈和PC,hotspot中java虚拟机栈和本地方法栈是一起的,都在本地内存空间中分配。
  8. 每一个java线程都有自己的私有java虚拟机栈,这个栈与线程同时创建,用于存储栈帧,栈帧中的存放的是局部变量,操作数以及返回结果和返回地址等。
  9. 因为JVM规范允许虚拟机栈大小固定或者可以扩展,所以如果大小固定,并且有线程请求分配的栈大小超出了虚拟机栈允许的最大容量时,会抛出StackOverFlowError;如果大小是可扩展的,那么如果扩展后的栈空间还是无法满足线程的请求,或者新的线程创建时没有足够的内存再去创建栈时,会抛出OutOfMemoryError
  10. hotspot的永久代也称为方法区,存放的java类的字段,字节码等。在对象分配工作完成的同时,运行时将对象的引用设置成栈帧中的明确的位置。栈帧是为方法服务的,方法在执行的时候需要访问哪个对象,就直接访问栈帧的指定位置。
  11. 每个java类文件中都定义了一组数据结构来表示类中出现的符号信息,这种数据结构就是常量池。常量池中的每一项都表示一个符号,每个符号都有在class中的唯一索引,字节码指令就是通过常量池索引来定位方法或者字段。常量池的作用类似于C语言中的符号表,jvm利用常量池实现类加载和链接阶段对符号引用的定位。
  12. 垃圾收集算法:
    1. 标记-清除算法:标记阶段标记出所有可以回收的对象,回收阶段进行回收并释放空间。
    2. 复制算法:将内存分为一个大的Eden和两个小的From和To,复制阶段将Eden中存活的对象复制到某一个survivor中,清除阶段清除Eden和另一个survivor,如果复制阶段一个survivor容纳不下所有的对象,则直接晋升到老年代。
    3. 标记-压缩算法:标记可以回收的对象,将对象移动到空间的另一端,释放剩余的空间。
  13. minor GC和full GC:minor GC对新生代进行回收,full GC除了对新生代和老年代,永久代都进行回收。
  14. 一般情况下,对象都在新生代的Eden区分配,当Eden区空间不够时,就会出发minor GC。在新生代的收集过程中,survivor用来暂存存活的对象,在复制环节所有的幸存者对象都会复制到这个区域,当这个survivor不能容纳下所有幸存对象的时候,允许一部分对象直接晋升至老年代。
  15. 一般来说首先出发minor GC来回收新生代,此时将使用复制算法,当老年代无法容纳新生代晋升来的对象时,将触发full GC,对整个堆进行回收。
  16. 当系统中有大量连续的空间时,可以使用碰撞指针算法来进行对象的内存空间分配,思路是记录上一次分配对象的位置,有新的对象要分配时,若检查剩余的空间可以容纳下这个对象,则只需要移动一次指针便能完成内存的分配。
  17. 在垃圾收集器完成GC后,内存中的已分配和未分配的空间时相对独立并且地址相连续的,则只需要记录上一次分配对象的末尾指针,分配新对象时只要检查空间满足,就可以移动一次指针完成对象分配。
  18. 在栈中分配是分析局部变量的作用域仅限于方法内部,所以直接在栈帧内分配对象空间,而不是在堆中。分析的过程称为逸出分析,这样可以减少新生代的收集次数,提高性能。
  19. 各种垃圾收集器
    1. Serial:单线程,所用于新生代,基于复制算法,STW时间长。
    2. Serial old:单线程,作用老年代,基于标记-整理算法,STW时间长。
    3. ParNew:多线程,作用于新生代,由于在STW期间是通过多线程进行收集的,所以STW时间比Serial短。
    4. ParNew old;多线程,老年代,标记-整理算法。
    5. CMS:以最小的停顿时间为目标,适用于交互响应速度敏感的程序,仅作用域老年代。CMS的创新之处是将标记阶段进行分解,根据粒度更小的操作阶段对STW的需求不同的特点。由于标记阶段才需要STW,标记完成后的回收是可以并行的。所以CMS讲标记分为两个阶段:初始标记和并发标记。初始标记从根节点对象开始仅扫描和根节点直接关联的对象并标记,会STW,但是由于根节点少,所以很快;并发标记阶段与用户线程并发执行,根据之前的标记开始向下追溯,不会STW;并发预清理阶段与应用线程并发,重新扫描判断时候有晋升的新对象并处理;重新标记阶段会STW,主要在前期 标记的基础上进行引用关系修复,保证引用关系是正确的;并发清理阶段并发的回收垃圾。CMS不适合新生代的原因是新生代对象的创建和死亡都比较频繁,所以应该用复制算法,而且CMS基于标记-清除算法,会出现很多内存碎片,所以不适合新生代。
  20. GC root与可达性:root对象是指由堆以外的空间中访问的对象,比如局部变量,栈中的对象,全局变量等。从root出发能够找到一条路径引用到对象,则是可达的。

猜你喜欢

转载自blog.csdn.net/lengyuedanhen/article/details/80253070