苏州网站开发公司鹅鹅鹅,短链接在线工具,做配件出口上什么网站,怎么制作网站vi页面面试 JVM 八股文五问五答第一期 作者#xff1a;程序员小白条#xff0c;个人博客 相信看了本文后#xff0c;对你的面试是有一定帮助的#xff01;
⭐点赞⭐收藏⭐不迷路#xff01;⭐
1.JVM内存布局 Heap (堆区#xff09;
堆是 OOM 故障最主要的发生区域。它是内存…面试 JVM 八股文五问五答第一期 作者程序员小白条个人博客 相信看了本文后对你的面试是有一定帮助的
⭐点赞⭐收藏⭐不迷路⭐
1.JVM内存布局 Heap (堆区
堆是 OOM 故障最主要的发生区域。它是内存区域中最大的一块区域被所有线程共享存储着几乎所有的实例对象、数组。
Java 堆是垃圾收集器管理的主要区域因此很多时候也被称做“GC 堆”。从内存回收的角度来看由于现在收集器基本都采用分代收集算法所以 Java 堆中还可以细分为新生代和老年代。再细致一点的有 Eden 空间、From Survivor 空间、To Survivor 空间等。从内存分配的角度来看线程共享的 Java 堆中可能划分出多个线程私有的分配缓冲区Thread Local Allocation Buffer,TLAB。不过无论如何划分都与存放内容无关无论哪个区域存储的都仍然是对象实例进一步划分的目的是为了更好地回收内存或者更快地分配内存。
堆区的调整通过设置如下参数可以设定堆区的初始值和最大值比如 -Xms256M -Xmx 1024M其中 -X 这个字母代表它是 JVM 运行时参数ms 是 memory start 的简称中文意思就是内存初始值mx 是 memory max 的简称意思就是最大内存。
在通常情况下服务器在运行过程中堆空间不断地扩容与回缩会形成不必要的系统压力所以在线上生产环境中 JVM 的 Xms 和 Xmx 会设置成同样大小避免在 GC 后调整堆大小时带来的额外压力。
堆的默认空间分配查看当前 JDK 版本所有默认的 JVM 参数》java -XX:PrintFlagsFinal -version
Java 虚拟机栈
对于每一个线程JVM 都会在线程被创建的时候创建一个单独的栈。也就是说虚拟机栈的生命周期和线程是一致并且是线程私有的。
栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。栈帧存储了方法的局部变量表(局部变量表:定义为一个数字数组,用于方法参数和方法内部的局部变量,包括三种数据类型:8种基本数据类型引用数据类型地址returnAddress类型(指向一条字节码指令的地址) )、操作数栈(操作数栈主要用于保存运算过程中的的中间结果,同时作为计算过程中变量的临时的存储空间.)、动态链接(动态链接就是讲指令中的符号引用转化为真实的方法地址(直接引用)和方法返回地址等信息。每一个方法从调用至执行完成的过程都对应着一个栈帧在虚拟机栈里从入栈到出栈的过程。
本地方法栈
本地方法栈Native Method Stack与虚拟机栈所发挥的作用是非常相似的它们之间的区别不过是虚拟机栈为虚拟机执行 Java 方法也就是字节码服务而本地方法栈则为虚拟机使用到的 Native 方法服务。在虚拟机规范中对本地方法栈中方法使用的语言、使用方式与数据结构并没有强制规定因此具体的虚拟机可以自由实现它。甚至有的虚拟机譬如 Sun HotSpot 虚拟机直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样本地方法栈区域也会抛出 StackOverflowError 和 OutOfMemoryError 异常。
拓展
静态链接:当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译器可知,且运行时期不变,这种情况下将调用方法的符号引用转换为直接引用的过程称之为静态链接.对应早期绑定(早期绑定就是指被调用的目标方法如果在编译期可知,且运行时期不变,即可将这个方法与所属的类型进行绑定,这样以来,由于明确了被调用的方法是哪一个,因此可以使用静态链接的方式将符号引用转换为直接引用).动态链接:如果被调用的方法在编译期无法被确定下来,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此被称之为动态链接.对应晚期绑定(如果被调用方法在编译期无法被确定下来,只能在程序运行期根据实际的类型绑定相应的方法,这种绑定方式被称为晚期绑定).
程序计数器
程序计数器Program Counter Register是一块较小的内存空间。是线程私有的。它可以看作是当前线程所执行的字节码的行号指示器
直接内存
直接内存Direct Memory并不是虚拟机运行时数据区的一部分也不是 Java 虚拟机规范中定义的内存区域。但是这部分内存也被频繁地使用而且也可能导致 OutOfMemoryError 异常出现
Code Cache
JVM 代码缓存是 JVM 将其字节码存储为本机代码的区域 。我们将可执行本机代码的每个块称为 nmethod。该 nmethod 可能是一个完整的或内联 Java 方法。
2.Java如何标记垃圾
Java中的垃圾回收是通过标记-清除算法实现的。当一个对象不再被任何引用指向时它就可以被垃圾回收器回收。
在Java中垃圾回收器通过可达性分析算法来标记垃圾对象。可达性分析算法是从一组被称为“GC Roots”的根对象开始遍历内存中的所有对象任何能够被遍历到的对象都被认为是“存活”的对象而未被遍历到的对象则被认为是“垃圾”对象。
Java中的GC Roots包括以下几种类型的对象
虚拟机栈中引用的对象方法区中静态属性引用的对象方法区中常量引用的对象本地方法栈中JNIJava Native Interface引用的对象
垃圾回收器会从GC Roots开始遍历内存中的所有对象标记出所有被引用的对象然后将没有被标记的对象视为垃圾对象进行回收。这个过程中需要注意的是垃圾回收器不能回收互相引用的对象即使这些对象已经没有任何被引用的路径因为它们之间仍然存在一条循环引用的路径所以它们仍然被视为“存活”的对象。
需要注意的是Java虚拟机的垃圾回收机制是自动的程序员无法直接干预。但是可以通过一些手段来优化垃圾回收的效率比如尽量避免创建大量的临时对象避免使用过多的finalize()方法等。
3.GC回收的是哪里
因为虚拟机栈、本地方法栈、程序计数器是线程私有的随着线程的消亡而消亡方法结束或者线程结束时内存自然就跟随着回收了。 GC回收的区域是堆和方法区为什么回收这两个区域那因为他们是线程共享的即java程序中所有的线程都可以访问。
4.常见的垃圾回收算法有哪些
**分代收集算法:**根据内存对象的存活周期不同将内存划分成几块java虚拟机一般将内存分成新生代和老生代在新生代中有大量对象死去和少量对象存活所以采用复制算法只需要付出少量存活对象的复制成本就可以完成收集;老年代中因为对象的存活率极高没有额外的空间对他进行分配担保所以采用标记清理或者标记整理算法进行回收;
**标记清除法:**第一步:利用可达性去遍历内存把存活对象和垃圾对象进行标记;
第二步:在遍历一遍将所有标记的对象回收掉;
特点:效率不行标记和清除的效率都不高;标记和清除后会产生大量的不连续的空间分片可能会导致之后程序运行的时候需分配大对象而找不到连续分片而不得不触发一次GC垃圾回收;
**标记整理法:**第一步:利用可达性去遍历内存把存活对象和垃圾对象进行标记;第二步:将所有的存活的对象向一段移动将端边界以外的对象都回收掉;
特点:适用于存活对象多垃圾少的情况;需要整理的过程无空间碎片产生;
**复制算法:**将内存按照容量大小分为大小相等的两块每次只使用一块当一块使用完了就将还存活的对象移到另一块上然后在把使用过的内存空间移除;特点:不会产生空间碎片;内存使用率极低;
5.哪些情况下会出现FULLGC
调用 System.gc()
只是建议虚拟机执行 Full GC但是虚拟机不一定真正去执行。不建议使用这种方式而是让虚拟机管理内存。
未指定老年代和新生代大小堆伸缩时会产生fullgc,所以一定要配置-Xmx、-Xms老年代空间不足
老年代空间不足的常见场景比如大对象、大数组直接进入老年代、长期存活的对象进入老年代等。
为了避免以上原因引起的 Full GC应当尽量不要创建过大的对象以及数组。
除此之外可以通过 -Xmn 虚拟机参数调大新生代的大小让对象尽量在新生代被回收掉不进入老年代。
还可以通过 -XX:MaxTenuringThreshold 调大对象进入老年代的年龄让对象在新生代多存活一段时间。
在执行Full GC后空间仍然不足则抛出错误java.lang.OutOfMemoryError: Java heap space
JDK 1.7 及以前的永久代空间满
在 JDK 1.7 及以前HotSpot 虚拟机中的方法区是用永久代实现的永久代中存放的为一些 Class 的信息、常量、静态变量等数据。
当系统中要加载的类、反射的类和调用的方法较多时永久代可能会被占满在未配置为采用 CMS GC 的情况下也
会执行 Full GC。
如果经过 Full GC 仍然回收不了那么虚拟机会抛出java.lang.OutOfMemoryError PermGen space
为避免以上原因引起的 Full GC可采用的方法为增大Perm Gen或转为使用 CMS GC。
空间分配担保失败
空间担保下面两种情况是空间担保失败
1、每次晋升的对象的平均大小 老年代剩余空间
2、Minor GC后存活的对象超过了老年代剩余空间
注意GC日志中是否有promotion failed和concurrent mode failure两种状况当出现这两种状况的时候就有可能会触发Full GC。
promotion failed 是在进行 Minor GC时候survivor space空间放不下只能晋升老年代而此时老年代也空间不足时发生的。
concurrent mode failure 是在进行CMS GC过程此时有对象要放入老年代而空间不足造成的这种情况下会退化使用Serial Old收集器变成单线程的此时是相当的慢的。