深入理解JVM内存分配机制

 2023-01-19
原文作者:AI码师 原文地址:https://juejin.cn/post/6889750832959455245

JVM整体结构

202301011701586721.png

  • 堆 线程共享的区域,也是垃圾回收器要收集的区域,这地方主要保存用户创建的对象。例如 new User(),这个对象是保存在堆上面的。

  • 栈 栈上面用来保存方法运行产生的局部变量、方法返回值和动态链接。

  • 本对方法栈 是用来保存本地方法(native)执行的栈结构

  • 方法区 在jdk1.8中已经更名为元空间了,这里面主要保存如下内容:

    • 类型信息

      • 类型的全限定名
      • 超类的全限定名
      • 直接超接口的全限定名
      • 类型标志(该类是类类型还是接口类型)
      • 类的访问描述符(public、private、default、abstract、final、static)
    • 类型的常量池

    • 字段信息

      • 字段修饰符(public、protect、private、default)
      • 字段的类型
      • 字段名称
    • 方法信息

    • 类变量

    • 各种引用

      • 类实例的引用
      • 加载器的引用
    • 方法表 方法表是以非抽象类为纬度创建的数组,数组里面的元素是类中每个方法的直接引用,提升访问效率。

  • 程序计数器 程序计数器是用来保存所在线程在切换前执行指令所在的行号,这个主要是解决多线程情况下,进行线程切换带来的问题,如果只有单线程,其实是不需要程序计数器的。

堆区域是如何进行划分的?

了接jvm的同学应该都知道,堆其实是分为新老年代的,这主要是为了进行垃圾回收而设计的一种结构

202301011701596672.png

新老年代相关jvm参数

  • -XX:NewRatio 设置新老年代比例,如-XX:NewRatio=5 代表 新老年代比例为1:5,新生代占用堆内存的1/6,老年代占用5/6;jvm默认新老年代为1:2;需要注意的是如果程序启动指定了-XX:MaxNewSize值,那么设置比例的参数就会失效,老年代的值则为堆内存大小减去MaxNewSize;
  • -XX:SurvivorRatio 设置新生代中eden和两个2个Survivo区域大小的比例,如-XX:SurvivorRatio=8,则eden:s1:s2=8:1:1,默认比例就是为8:1:1.

young GC发生在新生代中,FUll GC 发生在整个堆空间中,一般是老年代空间不够用就会出发FULL GC

逃逸分析

逃逸分析 主要用来分析方法内部的哪些对象是可以在在栈里面分配的,因为一般对象都是在堆中分配的,在堆中分配的对象,需要等待垃圾回收器进行回收,在回收之前会一直占用堆空间的,但是如果在一个方法内部,一个对象如果满足以下条件,是可以在栈中进行分配的:

  • 是局部变量
  • 没有将赋值给成员变量
  • 没有被当作返回值跳出去

在jdk1.7之前需要使用-XX:+DoEscapeAnalysis参数进行开启,jdk1.7默认开启逃逸分析,如果需要关闭也是使用-XX:+DoEscapeAnalysis 参数进行关闭

什么是即时编译技术

我们写说下JVM的运行模式有哪几种?

  • 解释模式 执行一行字节码就编译成一行机器码执行

    • 特点:使用解释模式,JVM启动速度快,但是执行执行命令慢,需要一行一行进行编译
  • 编译模式 先将所有字节码全部编译为机器码,然后一次性加载所有机器码执行

    • 特点:使用编译模式,JVM启动速度会稍微慢点,因为需要进行编译,但是执行的时候几乎不需要有任何消耗
  • 混合模式 使用解释模式执行代码,但是如果碰到一些热点或共用的代码片段,会采用编译模式执行,并且会将编译的内容缓存起来,减少重复编译,从而提高代码执行效率,这个也是JVM默认采用的编译模式,这个就是JIT(即时编译技术)

微信搜一搜【乐哉开讲】关注帅气的我,回复【干货领取】,将会有大量面试资料和架构师必看书籍等你挑选,包括java基础、java并发、微服务、中间件等更多资料等你来取哦。