017期JavaSE面试题十七JVM之内存模型

6次阅读

共计 2419 个字符,预计需要花费 7 分钟才能阅读完成。

开篇介绍

大家好,我是 Java 最全面试题库 的提裤姐,明天这篇是面试系列的第十七篇,次要总结了 JavaSE 中 JVM 相干面试题,这篇是 JVM 系列的第一篇,次要解说JVM 的内存模型,第二篇次要解说垃圾回收。在后续,会沿着第一篇开篇的常识线路始终总结上来,做到日更!如果我能做到百日百更,心愿你也能够跟着百日百刷,一百天养成一个好习惯。

说一下 JVM 内存模型及分区,每个区放什么?

JVM 分为:

  • 堆区
  • 栈区
  • 办法区

①办法区:次要是存储类信息,常量池 (static 量和 static 变量),编译后的代码(字节码) 等数据
②堆:初始化的对象,成员变量(那种非 static 的变量),所有的对象实例和数组都要在堆上调配
③栈:栈的构造是栈帧组成的,调用一个办法就压入一帧,帧下面存储局部变量表,操作数栈,办法进口等信息,局部变量表寄存的是 8 大根底类型加上一个援用类型,所以还是一个指向地址的指针
④本地办法栈:次要为 Native 办法服务
⑤程序计数器:记录以后线程执行的行号

总结:初始化的对象放在堆外面,援用放在栈外面,class 类信息常量池 (static 常量和 static 变量) 等放在办法区

JVM 内存区域次要分为:

  • 线程公有区(程序计数器、虚拟机栈、本地办法区)
  • 线程共享区(Java 堆、办法区)
  • 间接内存

说一下 Java 内存调配

  • 寄存器:无法控制。
  • 动态域:static 定义的动态成员。
  • 常量池:编译时被确定并保留在 . class 文件 中的 final 常量值 和一些文本润饰的符号援用(类和接口的全限定名, 字段的名称和描述符, 办法和名称和描述符)。
  • 非 RAM 存储: 硬盘等永恒存储空间。
  • 堆内存:new 创立的对象和数组, 由 Java 虚拟机主动垃圾回收器治理, 存取速度慢。
  • 栈内存: 根本类型的变量和对象的援用变量(堆内存空间的拜访地址), 速度快, 能够共享, 然而大小与生存期必须确定, 不足灵活性。

新生代中为什么要分为 Eden 和 Survivor?

如果没有 Survivor,Eden 区每进行一次 Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC. 老年代的内存空间远大于新生代,进行一次Full GC 耗费的工夫比 Minor GC 长得多, 所以须要分为 Eden 和 Survivor。
Survivor 的存在意义,就是缩小被送到老年代的对象,进而缩小 Full GC 的产生,Survivor 的预筛选保障,只有经验 16 次 Minor GC 还能在新生代中存活的对象,才会被送到老年代。
设置两个 Survivor 区最大的益处就是 解决了碎片化,刚刚新建的对象在 Eden 中,经验一次 Minor GC,Eden 中的存活对象就会被挪动到第一块 survivor space S0,Eden 被清空;等 Eden 区再满了,就再触发一次 Minor GC,Eden 和 S0 中的存活对象又会被复制送入第二块 survivor space S1(这个过程十分重要,因为这种复制算法保障了 S1 中来自 S0 和 Eden 两局部的存活对象占用间断的内存空间,防止了碎片化的产生)

对象如何降职到老年代?

1、大对象间接进入老年态
2、通过一次 Minor GC,年龄 +1,若年龄超过肯定限度(15),则被降职到老年态。即长期存活的对象进入老年态

元数据区寄存的是什么?会 oom 吗?

Perm Space 中保留的是 加载 class 文件

会引起 OutOfMemory,出现异常能够设置 -XX:PermSize 的大小。

JDK 1.8 后,字符串常量不寄存在永恒代,而是在堆内存中,JDK1.8 当前没有永恒代概念,而是用元空间代替,元空间不存在虚拟机中,二是应用本地内存。

jvm 加载 class 原理

JVM 中类的装载是由 类加载器(ClassLoader) 它的子类 来实现的,Java 中的类加载器是一个重要的 Java 运行时零碎组件,它负责在运行时查找和装入类文件中的类。

因为 Java 的跨平台性,通过编译的 Java 源程序并不是一个可执行程序,而是一个或多个类文件。当 Java 程序须要应用某个类时,JVM 会确保这个类曾经被加载、连贯(验证、筹备和解析)和初始化。

类的加载是指把类的.class 文件中的数据读入到内存中,通常是创立一个字节数组读入.class 文件,而后产生与所加载类对应的 Class 对象。加载实现后,Class 对象还不残缺,所以此时的类还不可用。当类被加载后就进入连贯阶段,这一阶段包含 验证 筹备 (为动态变量分配内存并设置默认的初始值)和 解析(将符号援用替换为间接援用)三个步骤。最初 JVM 对类进行初始化,包含:
①如果类存在间接的父类并且这个类还没有被初始化,那么就先初始化父类;
②如果类中存在初始化语句,就顺次执行这些初始化语句。类的加载是由类加载器实现的,类加载器包含:根加载器(BootStrap)、扩大加载器(Extension)、零碎加载器(System)和用户自定义类加载器(java.lang.ClassLoader 的子类)。从 Java 2(JDK 1.2)开始,类加载过程采取了父亲委托机制(PDM)。PDM 更好的保障了 Java 平台的安全性,在该机制中,JVM 自带的 Bootstrap 是根加载器,其余的加载器都有且仅有一个父类加载器。类的加载首先申请父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。JVM 不会向 Java 程序提供对 Bootstrap 的援用。

哪些区域可能会产生 oom?

内存区域 是否线程公有 是否会产生 OOM
程序计数器
虚拟机栈
本地办法栈
办法区
间接内存

Java 堆的构造是什么样子的?

JVM 的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存。
它在 JVM 启动的时候被创立。
对象所占的堆内存是由主动内存管理系统也就是垃圾收集器回收。
堆内存是由存活和死亡的对象组成的。
存活的对象是利用能够拜访的, 不会被垃圾回收。
死亡的对象是利用不可拜访尚且还没有被垃圾收集器回收掉的对象。
始终到垃圾收集器把这些对象回收掉之前, 他们会始终占据堆内存空间。

正文完
 0