banner
Hi my new friend!

JVM内存模型

Scroll down
  • JVM结构主要分为四个部分
  1. 类加载器
  2. 内存区域
  3. 执行引擎
  4. 本地库接口
  • 本地内存,直接内存
    本地内存和直接内存都不在jvm中,而是在本地,不受jvm管理.
    其中本地内存可以通过本地方法去分配和使用,而直接内存更是特殊,可以直接用java API进行调用,需要手动free,由于没有gc等,适合做大数据的缓冲例如: 网络通信等

  • JVM内存如何划分:

  1. 程序计数器(记录下一条指令地址)
  2. 虚拟机栈(栈帧为最小单元,内有局部变量表(基本数据类型和复杂类型的引用),操作数栈,返回地址,动态链接)
  3. 本地方法栈
  4. 堆(对象和方法的存储,字符串常量池(jdk7后))
  5. 元空间(jdk8) (运行时常量池,类的描述信息)

其中前三者为线程私有,每个线程都有各自的. 堆与元空间是线程共享的.

  • 堆的结构划分
    新生代和老年代(1:2)
    新生代又分为Eden区,survive0,survice1(又叫from和to)

    from和to不固定,谁空谁就是to
    比例为8:1:1
    新生代:老年代,以及新生代内部的内存比例都是可配的

  • 垃圾回收机制
    新生代 复制算法
    老年代 标记整理

  • 垃圾回收算法的优缺点

  1. 标记清除

    1. 首先通过可达性分析进行标记
    2. 然后遍历进行清除
      优点: 简单粗暴
      缺点: 遍历两次效率低,容易出现内存碎片

      产生内存碎片带来的影响:
      当来了一个大对象时,由于全是碎片,导致容纳不下,提前发起gc

  2. 标记整理
    优点: 不会产生内存碎片,较简单高效,内存使用率高
    缺点: 局部变量转移会导致效率变低

  3. 复制算法

    缺点:

    • 内存使用率低, 需要留下一半空间用于垃圾回收,因此正常存储只能使用不到一半的空间.
    • 当存活很多对象时,效率低
      优点: 不会产生内存碎片,简单高效
  • 如何判断对象是否存活
  1. 引用计数法
    就是为每个对象添加一个计数器,当该对象被引用的时候,就为计数器加一.当对象的引用失效(出作用域)后,计数器减一. 每当对象计数器减为0时,就回收. 当对象被回收时,其引用的对象的计数器减一
    缺点: 不能解决对象循环引用的场景, 引用计数器加大了开销
    优点: 执行简单,效率高,适合实时环境

    java程序没有采用引用计数法

  2. 可达性分析
    从GC Roots出发搜索,搜索过的路径为引用链.当对象不能通过引用链与GC root连通时,判定为不可达,可以回收
    优点: 可以解决对象循环引用的场景
    缺点: 相较而言实现复杂
  • 哪些可以做GC roots?
  1. 虚拟机栈中的引用
  2. 方法栈中的引用
  3. 元空间中类静态属性的引用
  4. 元空间中常量的引用
  • 讲一下hotSpot的垃圾收集器
    hotSpot中实现了多种垃圾收集器,并且没有哪个垃圾收集器是最好的,也没有哪个垃圾收集器是万能的.常见的有:

    • Serial收集器:
      单线程gc,同时应用程序需要暂停
    • ParNew(Serial的多线程版本)
      多线程gc,同时应用程序需要暂停
    • Parallel Scavenge
      多线程gc,新生代采用标记复制,注重吞吐量(处理用户代码的时间/所有时间)
    • Parallel Old:
      多线程gc,老年代采用标记整理算法
    • CMS:
      目标: 获得最短回收停顿时间,
      采用标记清除算法
      第一款可以让回收线程与用户线程基本上同时工作的收集器

      jdk9中已经被弃用CMS, G1收集器为JDK9后的默认收集器

    • G1:
      一款面向服务器的,主要针对多处理器,大内存的机器.满足GC时间的同时,还具备高吞吐量的特征
  • 默认的垃圾收集器
    jdk8以前:
    新生代:Parallel Scavenge 老年代:Parallel Old
    jdk9~21: 新生代老年代均采用G1

  • 什么时候触发minor gc(young gc)
    当eden区剩余空间不足以分配新对象时

  • 什么时候触发full gc
    当老年代中剩余空间不足以分配新对象时
    当老年代剩余空间小于进入老年代的对象的平均大小时

  • CMS的含义:
    Concurrent, Mark, Sweep

  • g1较CMS的优点
    g1采用标记整理,局部采用复制算法;不会产生内存碎片
    g1有时间预测模型,能精准控制回收时间.G1将堆分为多个Region,然后根据控制时间来选择回收收益最多的区域回收(不全堆扫描,增量回收)
    g1的清理线程与用户线程不并行,不会产生浮动垃圾

  • G1中的Remembered Set和Card Table
    都是用来处理Region中的引用关系.Remembered Set精细化的处理Region间的应用
    Card Table粗粒度的处理Region的引用,为Region标记’脏’,回收时优先处理’脏’的Region

  • 内存信息排查

  1. 拿到PID
    1
    2
    netstat -ano | findstr ${port} //windows
    netstat -ntlp | grep ${port} //linux
  2. jmap -heap ${PID}
  3. jstack ${PID}
  • 应用问题排查,假死排查等
  1. tcp问题排查
    netstat -ntlp | grep ${port}
    查看tcp状态是否异常,是否有大量的time_wait
  2. 内存信息排查
    内存快照,堆快照,栈快照
  • cpu过高排查
    top找到cpu过高的进程
    top -H -p ${pid}找到cpu不正常的线程

    1
    -H: 显示线程

    jstack 显示堆栈信息并使用线程号匹配,看是否有异常

  • 对象在内存中是如何存储的(存储布局)

  1. markword(8字节)
  2. class pointer(类型指针 4个字节)
  3. instance data(示例数据 4个字节)
  4. padding(对齐 总的字节数一定是8字节的整数倍)
  • 对象头主要包括什么
    markwork和class pointer都属于对象头
    markword三大信息:
  1. 锁信息
  2. hashcode
  3. gc信息
  • 对象怎么定位
    通过对象的引用怎么定位到对象的地址
    有两种方式:
  1. 句柄方式
    引用指向一个实例数据指针
    引用指向一个类型数据指针
    对象在内存中的位置变化时,引用不需要改变

  2. 直接指针:
    引用直接指向实例数据(实例数据中class pointer指向类型信息)
    好处: 快

其他文章