2021面试-JVM

2021面试-JVM

文章目录

  • 2021面试-JVM
  • JVM内存模型
    • 程序计数器(线程私有)
    • 虚拟机栈(线程私有)
    • 本地方法栈(线程私有)
    • 堆 (线程共享)
    • 方法区/永久代(线程共享)
  • MinorGC的过程(复制-清空-互换)
  • MajorGC的过程:
    • 产生OOM:
  • 老年代:
  • 垃圾回收
    • 如何确定对象已死?
    • 垃圾收集算法:
    • 垃圾收集器:
  • 多路复用IO模型
    • 相关参数:
      • 堆设置
      • 收集器设置
      • 垃圾回收统计信息
      • 并行收集器设置
      • 并发收集器设置
  • 类加载-反射
    • JVM类加载机制
    • 双亲委派:
      • 双亲委派的几个好处:
      • 双亲委派 “父子加载器”之间是继承关系吗?
      • ⭐️ 双亲委派是如何实现的 ?
      • 如何主动破坏双亲委派机制:
      • 双亲委派被破坏的列子
    • Person p = new Person()在内存中发生了什么?
    • 什么情况下创建的对象不在堆中?

JVM内存模型

程序计数器(线程私有)

  • Java方法指向字节码文件的行号指示器
  • Native方法为空
  • 这是虚拟机唯一一个没有OOM的区域

虚拟机栈(线程私有)

  • 是Java方法的执行的内存模型
  • 方法在执行的时候会创建一个栈帧:包含局部变量表,操作数栈,动态链接,方法返回地址。
  • 栈帧随着方法调用被创建,随着方法结束而销毁。

本地方法栈(线程私有)

  • 和虚拟机栈作用类似,区别是:虚拟机栈为Java方法服务,而本地方法栈是为Native方法服务
  • HotSpot VM将本地方法区和虚拟机栈合二为一。

堆 (线程共享)

  • 运行时数据区
  • 创建的对象和数组都是保存在Java堆内存中。
  • 堆也是垃圾收集器进行垃圾回收的最重要区域。
  • 从GC的角度分为:新生代(Eden,From Survivor,To Survivor)和老年代

方法区/永久代(线程共享)

  • 用于存储JVM加载的类信息。常量和静态变量,即时编译后的代码数据。
  • 包含运行时常量池,用于存放各种字面量和符号引用。

MinorGC的过程(复制-清空-互换)

  • MinorGC采用复制算法
  • eden,from复制到to区 , 年龄+1
  • 清空eden,from
  • to和from互换

MajorGC的过程:

  • 首先扫描一次老年代,标记出存活的对象,回收没有标记的对象。
  • 耗时比较长,会产生内存碎片

产生OOM:

  • 永久带,GC不会在主程序运行期间对永久带进行清理,所以随着加载class的增多而胀满,最终抛出OOM
  • 老年代,当有大的对象老年代装不下的是就会抛出OOM

老年代:

  • 存放应用周期长的内存对象

垃圾回收

如何确定对象已死?

  • 引用计数法:会产生循环引用的问题
  • 可达性分析法:
    • 通过GCroots作为起点,向下搜索,当对象没有任何的引用链相连,说明已经死亡。
    • VM栈中的引用 — 方法区的静态引用 ---- JNI中的引用

垃圾收集算法:

  • 标记清楚法 : 效率低,内存碎片多
    • 标记:标记处需要回收的对象
    • 清除:清除被标记的对象所占用的空间
  • 复制算法:
    • 将内存分为均等的两块,每次只使用一块,
    • 当一块满了复制存活的对象到另一块
    • 把已使用的清除掉
  • 标记整理算法:
    • 结合了上面两种算法
    • 标记阶段和标记清除差不多,标记后不清理对象,而是将存活的对象移到另一端
    • 然后清除端边界外的对象。
  • 分代收集法:
    • 新生代采用复制算法
      • 每次只有少量的存活对象,只需付出少量的复制成本就可以完美收集
      • 每次只使用eden和from区,将存活的复制到to区
    • 老年代采用标记整理算法
      • 当对象在Survivor区躲过一次GC后,其年龄+1, 默认下年龄到达15的对象移到老年代

垃圾收集器:

  • Serial
    • 最基本的垃圾收集器,单线程,复制算法
    • Client模式下新生代的垃圾回收器
  • ParNew
    • Serial收集器的多线程版本, 复制算法
    • -XX:ParallelGCThreads参数限定线程数
    • Server模式下新生代默认的垃圾回收器
  • Parallel Scavenge
    • 多线程复制算法、高效
    • 利用高吞吐量高效的利用CPU时间
  • Serial Old
    • 单线程,标记整理算法
    • Client默认老年代垃圾收集器
    • Server模式下:
      • 与新生代的Parallel Scavenge搭配使用
      • 作为老年代CMS的后备垃圾收集方案
  • Parallel Old
    • 多线程, 标记整理算法
  • CMS - Concurrent Mark Sweep
    • 多线程,标记清除算法
  • G1: Garbage first
    • 标记整理算法,不产生内存碎片
    • 非常精准的停顿时间,不牺牲吞吐量的前提下, 实现低停顿垃圾回收

多路复用IO模型

  • 会有一个线程不断的轮询多个socket的状态,只有当socket真正有读写事件的时候,
  • 才真正调用实际的IO读写操作。

相关参数:

堆设置

  • -Xms:初始堆大小
  • -Xmx:最大堆大小
  • -XX:NewSize=n:设置年轻代大小
  • -XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
  • -XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
  • -XX:MaxPermSize=n:设置持久代大小

收集器设置

  • -XX:+UseSerialGC:设置串行收集器
  • -XX:+UseParallelGC:设置并行收集器
  • -XX:+UseParalledlOldGC:设置并行年老代收集器
  • -XX:+UseConcMarkSweepGC:设置并发收集器

垃圾回收统计信息

  • -XX:+PrintGC
  • -XX:+PrintGCDetails
  • -XX:+PrintGCTimeStamps
  • -Xloggc:filename

并行收集器设置

  • -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
  • -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
  • -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

并发收集器设置

  • -XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
  • -XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

类加载-反射

JVM类加载机制

  • 加载-验证-准备-解析-初始化
    • 加载: 在内存中生成一个代表这个类的对象,作为方法区这个类的数据入口。
    • 验证: 确保class文件的字节流中包含的信息是否符合当前虚拟机的要求
    • 准备: 在方法区中分配变量所使用的内存空间。初始化阶段为默认值
    • 解析: 虚拟机将常量池中的符合引用替换为直接引用的过程
    • 初始化: 真正执行类中定义的Java程序代码
      • 初始化是执行类构造器的过程
        • 启动类加载器: Bootstrap ClassLoader
        • 拓展类加载起: Extension ClassLoader
        • 应用程序类加载器: Application ClassLoader
        • 用户自定义加载器: User ClassLoader

双亲委派:

  • 当一个类收到类加载请求,它首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,
  • 每一层类加载器都是如此。
  • 只有当父类反馈自己无法完成这个请求的时候,子类加载器才会尝试自己去加载。
  • 目的是:保证不同的类加载最终得到的是同一个object对象。

双亲委派的几个好处:

  • 可以避免类的重复加载
  • 保证了安全性

双亲委派 “父子加载器”之间是继承关系吗?

双亲委派模型中,类加载器之间的父子关系一般不会以继承的关系来实现,而都是使用组合的关系来复用父加载器的代码

⭐️ 双亲委派是如何实现的 ?

  • 先检查类是否已经被加载过
  • 若没有加载则调用父类加载器的loadClass()进行加载
  • 若父类加载器为空,则默认使用启动类加载器作为父加载器
  • 若父类加载失败,抛出ClassNotFoundException异常后,在调用自己的findClass()进行加载

如何主动破坏双亲委派机制:

  • 自定义一个类加载器
  • 重写其中的loadClass()方法,使其不进行向上委派即可

双亲委派被破坏的列子

    1. 双亲委派出现之前:JDK1.2之后才引入的,在这之前是没有遵守的
    1. JNDI,JDBC等需要加载SPI接口实现类的情况。
    1. 为了实现热插拔热部署的工具。
    1. Tomcat等容器的出现
    1. OSGI,Jigsaw等模块化技术的应用

Person p = new Person()在内存中发生了什么?

  • 将Person.class文件加载进内存中。
  • 在栈中为p开辟一个变量空间
  • 在堆中为对象分配空间
  • 对对象中的成员变量进行初始化
  • 调用静态代码块,非静态代码块对象进行初始化(没有就不执行)
  • 调用构造方法对对象进行初始化,对象初始化完毕
  • 将对象的内存地址赋值给p变量,让p变量指向该对象。

什么情况下创建的对象不在堆中?

  • jit编译器下的逃逸分析算法会分析类使用情况

热门文章

暂无图片
编程学习 ·

那些年让我们目瞪口呆的bug

程序员一生与bug奋战,可谓是杀敌无数,见怪不怪了!在某知识社交平台中,一个“有哪些让程序员目瞪口呆的bug”的话题引来了6700多万的阅读,可见程序员们对一个话题的敏感度有多高。 1、麻省理工“只能发500英里的邮件” …
暂无图片
编程学习 ·

redis的下载与安装

下载redis wget http://download.redis.io/releases/redis-5.0.0.tar.gz解压redis tar -zxvf redis-5.0.0.tar.gz编译 make安装 make install快链方便进入redis ln -s redis-5.0.0 redis
暂无图片
编程学习 ·

《大话数据结构》第三章学习笔记--线性表(一)

线性表的定义 线性表:零个或多个数据元素的有限序列。 线性表元素的个数n定义为线性表的长度。n为0时,为空表。 在比较复杂的线性表中,一个数据元素可以由若干个数据项组成。 线性表的存储结构 顺序存储结构 可以用C语言中的一维数组来…
暂无图片
编程学习 ·

对象的扩展

文章目录对象的扩展属性的简洁表示法属性名表达式方法的name属性属性的可枚举性和遍历可枚举性属性的遍历super关键字对象的扩展运算符解构赋值扩展运算符AggregateError错误对象对象的扩展 属性的简洁表示法 const foo bar; const baz {foo}; baz // {foo: "bar"…
暂无图片
编程学习 ·

让程序员最头疼的5种编程语言

世界上的编程语言,按照其应用领域,可以粗略地分成三类。 有的语言是多面手,在很多不同的领域都能派上用场。大家学过的编程语言很多都属于这一类,比如说 C,Java, Python。 有的语言专注于某一特定的领域&…
暂无图片
编程学习 ·

写论文注意事项

参考链接 给研究生修改了一篇论文后,该985博导几近崩溃…… 重点分析 摘要与结论几乎重合 这一条是我见过研究生论文中最常出现的事情,很多情况下,他们论文中摘要部分与结论部分重复率超过70%。对于摘要而言,首先要用一小句话引…
暂无图片
编程学习 ·

安卓 串口开发

上图: 上码: 在APP grable添加 // 串口 需要配合在项目build.gradle中的repositories添加 maven {url "https://jitpack.io" }implementation com.github.licheedev.Android-SerialPort-API:serialport:1.0.1implementation com.jakewhart…
暂无图片
编程学习 ·

2021-2027年中国铪市场调研与发展趋势分析报告

2021-2027年中国铪市场调研与发展趋势分析报告 本报告研究中国市场铪的生产、消费及进出口情况,重点关注在中国市场扮演重要角色的全球及本土铪生产商,呈现这些厂商在中国市场的铪销量、收入、价格、毛利率、市场份额等关键指标。此外,针对…
暂无图片
编程学习 ·

Aggressive cows题目翻译

描述&#xff1a; Farmer John has built a new long barn, with N (2 < N < 100,000) stalls.&#xff08;John农民已经新建了一个长畜棚带有N&#xff08;2<N<100000&#xff09;个牛棚&#xff09; The stalls are located along a straight line at positions…
暂无图片
编程学习 ·

剖析组建PMO的6个大坑︱PMO深度实践

随着事业环境因素的不断纷繁演进&#xff0c;项目时代正在悄悄来临。设立项目经理转岗、要求PMP等项目管理证书已是基操&#xff0c;越来越多的组织开始组建PMO团队&#xff0c;大有曾经公司纷纷建造中台的气质&#xff08;当然两者的本质并不相同&#xff0c;只是说明这个趋势…
暂无图片
编程学习 ·

Flowable入门系列文章118 - 进程实例 07

1、获取流程实例的变量 GET运行时/进程实例/ {processInstanceId} /变量/ {变量名} 表1.获取流程实例的变量 - URL参数 参数需要值描述processInstanceId是串将流程实例的id添加到变量中。变量名是串要获取的变量的名称。 表2.获取流程实例的变量 - 响应代码 响应码描述200指…
暂无图片
编程学习 ·

微信每天自动给女[男]朋友发早安和土味情话

微信通知&#xff0c;每天给女朋友发早安、情话、诗句、天气信息等~ 前言 之前逛GitHub的时候发现了一个自动签到的小工具&#xff0c;b站、掘金等都可以&#xff0c;我看了下源码发现也是很简洁&#xff0c;也尝试用了一下&#xff0c;配置也都很简单&#xff0c;主要是他有一…
暂无图片
编程学习 ·

C语言二分查找详解

二分查找是一种知名度很高的查找算法&#xff0c;在对有序数列进行查找时效率远高于传统的顺序查找。 下面这张动图对比了二者的效率差距。 二分查找的基本思想就是通过把目标数和当前数列的中间数进行比较&#xff0c;从而确定目标数是在中间数的左边还是右边&#xff0c;将查…
暂无图片
编程学习 ·

项目经理,你有什么优势吗?

大侠被一个问题问住了&#xff1a;你和别人比&#xff0c;你的优势是什么呢? 大侠听到这个问题后&#xff0c;脱口而出道&#xff1a;“项目管理能力和经验啊。” 听者抬头看了一下大侠&#xff0c;显然听者对大侠的这个回答不是很满意&#xff0c;但也没有继续追问。 大侠回家…
暂无图片
编程学习 ·

nginx的负载均衡和故障转移

#注&#xff1a;proxy_temp_path和proxy_cache_path指定的路径必须在同一分区 proxy_temp_path /data0/proxy_temp_dir; #设置Web缓存区名称为cache_one&#xff0c;内存缓存空间大小为200MB&#xff0c;1天没有被访问的内容自动清除&#xff0c;硬盘缓存空间大小为30GB。 pro…
暂无图片
编程学习 ·

业务逻辑漏洞

身份认证安全 绕过身份认证的几种方法 暴力破解 测试方法∶在没有验证码限制或者一次验证码可以多次使用的地方&#xff0c;可以分为以下几种情况︰ (1)爆破用户名。当输入的用户名不存在时&#xff0c;会显示请输入正确用户名&#xff0c;或者用户名不存在 (2)已知用户名。…