栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java虚拟机-面试

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java虚拟机-面试

运行时数据区域 1、线程私有
  • 程序计数器:当前线程所执行的字节码的行号指示器,Java方法,记录正在执行的虚拟机字节码指令的地址,native方法,计数器值为空,唯一一个没有规定OutOfMemoryError的区域;
  • Java虚拟机栈:Java方法执行的内存模型,方法执行创建一个栈帧,存储:局部变量表、操作数栈、动态链接、方法出口等信息,方法调用到完成,对应栈帧在虚拟机栈中的入栈到出栈的过程;(StackOverflowError、OutOfMemoryError)
  • 本地方法栈:执行native方法服务,(StackOverflowError、OutOfMemoryError)
2、线程共享
  • 堆:对象实例、数组分配内存的地方,新生代(1/3)(Eden空间,From Survivor空间,To Survivor空间,比例为 8:1:1)、老年代(2/3);(OutOfMemoryError)
  • 方法区:类信息、常量、静态变量、运行时常量池;(OutOfMemoryError)

对象 1、对象创建分配空间方式

跟垃圾收集器是否有压缩整理功能相关;

  • 堆内存规整:用指针碰撞(指针分界点,往空闲的移动),CAS配上重试方式保证更新原子性
  • 堆内存不规则:空闲列表(记录哪些内存块可用)
2、对象的内存布局
  • 对象头:

        第一部分:存储对象自身的运行时数据、哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向锁ID、偏向时间戳(32、64bit),官方称为:Mark Word;

        第二部分:类型指针,指向它的类元数据的指针,确定对象是哪个类的实例

        第三部分:如果对象是一个数组,有一块记录数组长度的数据

  • 实例数据

        属性的字段内容

  • 对齐填充:不是必然存在,起占位符的作用,为了使对象的大小是8字节的整数倍;
3、对象的访问定位
  • 使用句柄:reference存储对象的句柄地址,稳定的句柄地址,句柄中包含了对象的实例数据和类型数据的地址信息,如果对象移动则只需改变句柄中实例数据的指针,而reference不用修改;
  • 直接指针:reference存的对象的实例地址,少一次指针定位;

垃圾收集器与内存分配策略 1、对象是否可回收判断方式
  • 引用计数法(很难解决对象之间的互相循环引用)
  • 可达性算法分析(GC roots),以被称为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,一个对象到GC Roots 没有引用链 则被认为不可用;(虚拟机栈栈帧中的本地变量表中引用的对象,方法区中类静态属性引用的对象,方法区中常量引用的对象,本地方法栈中native方法引用的对象);
  • 回收方法区:该类的所有实例已经被回收,加载该类的ClassLoader已经被回收,该类的Class对象没有任何地方被引用;
2、四种引用使用场景
  • 强引用:强引用还在,垃圾回收器不回收;
  • 软引用:系统内存不足,垃圾回收时会回收;
  • 弱引用:下次垃圾收集发生,会回收;
  • 虚引用:对象被垃圾收集器回收时收到一个通知;

3、垃圾收集算法
  • 复制:代价,内存缩小为原来的一半;
  • 标记-清除:效率问题,标记和清除两个过程的效率都不高;空间问题,标记清除之后,会产生大量空间碎片;
  • 标记-整理:所有存活的对象移到一端;
  • 分代收集:结合各个年代使用不同的收集算法;新生代:复制算法,老年代:标记整理或标记清除
4、垃圾收集器

新生代收集:

  • Serial收集器:单线程,一条收集线程去收集,暂停工作线程(Stop the World),简单高效;(复制算法、多线程) (配合 SerialOld和CMS)
  • ParNew收集器:Serial的多线程版本,使用多线程进行垃圾收集;(复制算法,多线程)(配合 SerialOld和CMS)
  • ParallelScavenge收集器:关注吞吐量,吞吐量优先的收集器,可设置,最大垃圾收集停顿时间(复制算法,并行的多线程收集),动态调节合适的停顿时间和最大吞吐量,自适应调节策略;(配合 SerialOld和Parallel Old)

老年代收集:

  • Serial Old:单线程、标记-整理
  • parallel old:多线程版本-标记-整理
  • CMS:最短回收停顿时间,注重响应速度,标记-清除,初始标记、并发标记、重新标记、并发清除;初始标记和重新标记需要Stop the world,对CPU资源敏感(线程数=(cpu+3)/ 4),浮动垃圾,边收集,用户还在运行产生新的垃圾只能下次收集,需要预留(用户和收集线程并发)空间,大量空间碎片产生(标记-清除算法)
  • G1:并行与并发,分代收集(可以独立管理不用和其他收集器配合),空间整合(从整体看是标记-整理算法,局部两个Region之间是复制算法,不会有空间碎片),可预测的停顿,堆分为多个大小相等的独立区域,优先回收价值最大的Region;初始标记、并发标记、最终标记、筛选回收(可独立的)
5、内存分配回收策略
  • 优先Eden分配,不足 则 MinorGC,Eden存活+From之前的到To(足够),不足则分配担保进入老年代,不能fullGC;
  • 大对象直接进入老年代(配置参数)
  • 长期存活的对象进入老年代(默认15岁)
  • 动态年龄判定:Survivor空间中相同年龄所有对象大小的综合大于Survivor空间的一半,年龄大于等于改年龄的对象直接进入老年代;
  • 空间分配担保,为了保证MinorGC安全,先检查老年代连续空间是否大于新生代所有对象总空间,如果大于则安全,否则检查是否设置了运行担保失败,如果允许,则会检查老年代空间是否大于历次晋升到老年代对象的平均大小,大于则MinorGC,小于则FullGC;

虚拟机类加载机制 1、类加载时机

类生命周期:加载、验证、准备、解析、初始化、使用、卸载

五种情况必须对类进行初始化:(对一个类进行主动引用)

  • new、getstatic、putstatic、invokestatic 使用new关键字实例化对象,读取或者设置一个类的静态字段、调用一个类的静态方法
  • 反射调用,如果没有对类进行初始化,需要触发初始化
  • 当初始化一个类时,发现其父类还没进行初始化,先触发父类的初始化
  • 虚拟机启动时,用户需要指定一个执行的主类(包含main方法的那个类),虚拟机会先初始化这个主类
  • 动态语言支持

被动引用不初始化:

使用子类调用父类的静态字段,子类不初始化,父类初始化;

数组定义引用类,不会触发类的初始化;

引用定义的常量的类,不会触发类的初始化(静态字段字符串);

加载:通过类的全限定名,生成class对象

验证:文件格式验证、元数据验证、字节码验证、符号引用验证

准备:类变量分配内存并设置初始值

解析:常量池内的符号引用改为直接引用

2、类加载器与双亲委派模型
  • 启动类加载器:rt.jar
  • 扩展类加载器:ext
  • 应用程序类加载器:classpath中类库(用户类、第三方引用jar)

加载器 先去找父类的加载(从缓存中找)找到就返回,找不到,到顶部后看类路径中有没有,有则加载,没有则交给下一个子类加载器加载,直到最后么有找到则报错;

高效并发

1、volatile特性

  • 保证此变量对所有线程的可见性(运算并发不一定安全,非原子)
  • 禁止指令重排序优化

2、线程状态

  • 新建:创建后未启动的线程;
  • 运行:可能正在执行或者等待CPU为他分配执行时间;
  • 无限期等待:不会分配CPU执行时间,等待被其他线程显式的唤醒;
  • 限期等待:一定时间后系统自动唤醒
  • 阻塞:等待获取排他锁
  • 结束:

等待和阻塞的区别:阻塞等待进入同步区域,等待获取一个排他锁(竞争锁),等待,等待一段时间或等待唤醒动作的发生;

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/980877.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号