Java常见面试题-05-jvm

JDK1.8 JVM 运行时内存

在这里插入图片描述

  • 程序计数器(线程私有的, 是一个指针. 代码运行, 执行命令. 而每个命令都是有行号的,会使用程序计数器来记录命令执行到多少行了.记录代码执行的位置)
  • Java 虚拟机栈(线程私有的. 一个方法运行, 就会给这个方法创建一个栈帧, 栈帧入栈执行代码, 执行完毕之后出栈存引用变量,基本数据类型)
  • 本地方法栈(线程私有的, 和 Java 虚拟机栈类似, Java 虚拟机栈加载的是普通方法,本地方法加载的是 native 修饰的方法)
  • (线程共享的. 存放对象的,new 的对象都存储在这个区域.还有就是常量池)
  • 元空间(存储.class 信息, 类的信息,方法的定义,静态变量等.而常量池放到堆里存储)

JDK1.8 堆内存结构

在这里插入图片描述

  • Young 年轻区(代): Eden+S0+S1, S0 和 S1 大小相等, 新创建的对象都在年轻代
  • Tenured 年老区: 经过年轻代多次垃圾回收存活下来的对象存在年老代中.

Gc 垃圾回收

JVM 的垃圾回收动作可以大致分为两大步,首先是「如何发现垃圾」,然后是「如何回收垃圾」。说明一点, 线程私有的不存在垃圾回收, 只有线程共享的才会存在垃圾回收, 所以堆中存在垃圾回收.

如何发现垃圾:

  1. 引用计数算法
    堆中的对象每被引用一次,则计数器加 1, 每减少一个引用就减 1,当对象的引用计数器为 0 时可以被当作垃圾收集。
    优点:快。
    缺点:无法检测出循环引用。如两个对象互相引用时,他们的引用计数永远不可能为 0。

  2. 根搜索算法(也叫可达性分析)
    把所有的引用关系看作一张图,从一个节点 GC ROOT 开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即可以当作垃圾。
    Java 中可作为 GC Root 的对象有

    • 虚拟机栈中引用的对象
    • 本地方法栈引用的对象
    • 方法区中静态属性引用的对象
    • 方法区中常量引用的对象

如何回收垃圾

  • 标记-清除算法(mark and sweep)
    分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成之后统一回收掉所有被标记的对象。
    缺点:首先,效率问题,标记和清除效率都不高。其次,标记清除之后会产生大量的不连续的内存碎片。

  • 标记-整理算法
    是在标记-清除算法基础上做了改进,标记阶段是相同的,但标记完成之后不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,在移动过程中清理掉可回收的对象,这个过程叫做整理。
    优点:内存被整理后不会产生大量不连续内存碎片。

  • 复制算法(copying)
    将可用内存按容量分成大小相等的两块,每次只使用其中一块,当这块内存使用完了,就将还存活的对象复制到另一块内存上去,然后把使用过的内存空间一次清理掉。
    缺点:可使用的内存只有原来一半。

  • 分代收集算法(generation)
    当前主流 JVM 都采用分代收集(Generational Collection)算法, 这种算法会根据对象存活周期的不同将内存划分为年轻代、年老代、永久代,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。
    (1) 年轻代(Young Generation)

    1. 所有新生成的对象首先都是放在年轻代的。
      2.年轻代内存按照8:1:1 的比例分为一个eden 区和两个Survivor(survivor0,survivor1)区。大部分对象在 Eden 区中生成。回收时先将 eden 区存活对象复制到一个 survivor0 区, 然后清空 eden 区,当这个 survivor0 区也存放满了时,则将 eden 区和 survivor0 区存活对象复制到另一个 survivor1 区,然后清空 eden 和这个 survivor0 区,此时 survivor0 区是空的,然后将 survivor0 区和 survivor1 区交换,即保持 survivor1 区为空, 如此往复。
    2. 当 survivor1 区不足以存放 eden 和 survivor0 的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次 Full GC,也就是年轻代、老年代都进行回收。
    3. 年轻代发生的 GC 也叫做 Minor GC,MinorGC 发生频率比较高(不一定等 Eden 区满了才触发)

    (2) 年老代(Old Generation)

    1. 在年轻代中经历了 N 次垃圾回收后仍然存活的对象,就会被放到年老代中。因此, 可以认为年老代中存放的都是一些生命周期较长的对象。
    2. 内存比新生代也大很多(大概是 2 倍),当老年代内存满时触发 Major GC 即 Full GC, Full GC 发生频率比较低,老年代对象存活时间比较长,存活率比较高。

    (3) 持久代(Permanent Generation)
    用于存放静态文件,如 Java 类、方法等。持久代对垃圾回收没有显著影响,从 JDK8 以后已经废弃, 将存放静态文件,如 Java 类、方法等这些存储到了元数据区.

JVM 调优参数

  • -Xmx3550m:设置 JVM 最大可用内存为 3550M。
  • -Xms3550m:设置 JVM 初始内存为 3550m。注意:此值一般设置成和-Xmx 相同, 以避免每次垃圾回收完成后 JVM 重新分配内存。
  • -Xmn2g:设置年轻代大小为 2G。整个 JVM 内存大小=年轻代大小 + 年老代大小 + 持久代大小。此值对系统性能影响较大,Sun 官方推荐配置为整个堆的 3/8。
  • -Xss256k:设置每个线程的栈大小。JDK5.0 以后每个线程栈大小为 1M,以前每个线程栈大小为 256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。
  • -XX:NewRatio=4:设置年轻代(包括 Eden 和两个 Survivor 区)与年老代的比值(除去持久代)。设置为 4,则年轻代与年老代所占比值为 1:4。(该值默认为 2)
  • -XX:SurvivorRatio=4:设置年轻代中 Eden 区与 Survivor 区的大小比值。设置为 4, 则两个 Survivor 区与一个 Eden 区的比值为 2:4。

欢迎java热爱者了解文章,作者将会持续更新中,期待各位友友的关注和收藏。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿胡爱编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值