Skip to content

Latest commit

 

History

History
105 lines (71 loc) · 5.59 KB

JVM.md

File metadata and controls

105 lines (71 loc) · 5.59 KB

JVM

JVM的内存结构?

  • 堆:对象实体、数组、字符串常量池,被线程共享(static修饰的基本数据类型也存在这里)
  • 本地方法栈:native方法相关的栈
  • 虚拟机栈:局部变量、基本类型数据、对象的引用
  • PC:定位程序,用于流程控制、线程切换
  • 方法区:类的信息、运行时常量池,被线程共享
方法区
用来存储加载的类信息常量静态变量编译后的代码等数据堆内存
堆内存可以细分为老年代新生代(EdenFrom SurvivorTo Survivor)。JVM启动时创建用来存放对象的实例堆内存是垃圾收集器管理的主要区域虚拟机栈
线程私有的虚拟机栈由多个栈帧组成一个线程会执行一个或多个方法一个方法对应一个栈帧每一次方法调用都会有一个对应的栈帧被压入栈中每一个方法调用结束后都会有一个栈帧被弹出栈帧内容包含局部变量表操作数栈动态链接方法返回地址等信息本地方法栈
和虚拟机栈功能类似虚拟机栈是为虚拟机执行JAVA方法而准备的本地方法栈是为虚拟机使用Native本地方法而准备的程序计数器
线程私有的程序计数器主要有两个作用作为当前线程所执行的字节码的行号指示器通过它实现代码的流程控制顺序执行分支循环异常处理在多线程的情况下程序计数器用于记录当前线程执行的位置当线程被切换回来的时候可以通过程序计数器中的信息获取上次执行的位置然后继续执行

异常有哪些?

  • StackOverFlow:线程所请求的栈的深度超过了JVM允许的深度
  • OutOfMemory:栈是无限延伸的,动态申请栈时无法申请到足够的内存空间

对象的创建过程?

  1. 类加载检查
  2. 分配内存
    • 指针碰撞:用于堆规整,将堆分为已使用和未使用,中间有一个指针来表明边界,移动指针即可完成内存分配
    • 空闲列表:用于堆不规整,将空闲空间用链表串起来,在分配对象的内存空间时从中找出可以用于分配的内存区域
  3. 0初始化:将对象的所有位填0,以便未为对象赋值也能知道每个对象的默认信息
  4. 设置对象头信息:包括它是属于哪一个类的对象、如何找到这个类的元信息、GC-age、哈希码等
  5. 执行方法,把对象按照程序员的意愿初始化

对象的内存布局?

  • 对象头:
    • 对象信息(锁状态、GC分代年龄、哈希码)
    • 类型指针
  • 实例数据
  • 对齐填充:占位

对象访问定位的方式?

  • 句柄:reference存放的是句柄地址,句柄指向实例和类信息,在对象实例发生改变时只需要移动到对象实例的指针

    对象的访问定位-使用句柄

  • 指针:reference中存储的是对象的地址,速度快,节省了一次指针定位的开销

对象的访问定位-直接指针

有哪些GC算法?

  • 标记-清除:分为两个阶段,先标记所有需要清除的对象,然后再清除
    • 优点:简单
    • 缺点:效率低,容易产生内存碎片
  • 标记-复制:分成两块区域,一块存放对象,一块不存放对象。将存活对象复制到未存放区域,然后对原先的存放区域整块进行清除
    • 优点:简单高效
    • 缺点:空间开销大;不适合老年代,因为老年代对象一般占用内存较大,复制开销大
  • 标记-整理:和"标记-清除"一样都是先标记,不同是该算法将所有存活对象移向一段,再将端边界外的内存进行清理,适合老年代这种复制频率不高的情景
  • 分代收集:新生代清除频率高,采用标记-复制,只需要付出少量对象的复制成本就可以完成每次垃圾收集,不会产生过多内存碎片;老年代采用标记-整理或标记-清除

判断对象是否死亡

  • 引用计数器法:给每个对象添加一个计数器,被引用了就+1,引用数为0即死亡,简单高效,但存在循环引用的问题,Java不采用

  • 根搜索算法:选择一个对象作为GC-Roots根节点,从此节点往下搜索引用链,若对象不在该链上说明对象死亡

    哪些节点可以成为GC-Roots?

    • 栈中保存的引用对象
    • Native栈中的引用对象
    • 方法区中的静态引用对象
    • 方法区中的常量引用

有哪些垃圾回收收集器?

  • Serial:单线程,新生代标记-复制,老年代标记-整理,暂停所有用户线程

  • ParNew:多线程版的Serial,JDK1.8默认

  • CMS(Concurrent Mark Sweep):真正意义上的多线程,用户线程与GC线程并发,并发收集、低停顿,但它对CPU资源敏感、无法收集浮动垃圾,M-S会产生大量内存碎片,JDK9废

  • G1:自JDK9后默认,针对多核大容量机器,在停顿时间短的同时吞吐量高

    • 并行与并发:能充分利用多核,无需暂停java(用户)线程
    • 分代收集
    • 空间整合:总体采用标记-整合,局部标记-清理,减少了内存碎片的产生
    • 可预测的停顿

    为什么叫Garbage-First?

    • 在后台维护了一个优先队列,每次根据允许的收集时间,优先收集价值最高的region