Java面试--jvm

JVM

1.jvm作用?

首先编译器将Java代码编译成字节码文件,通过类加载器加载到运行时数据区的方法区中。字节码是JVM的一套指令规范,并不能直接交给操作系统区执行,所以需要特定的jvm执行引擎将字节码翻译成底层系统指令,再交给cpu去执行。

2.jvm重要组成部分?

由类加载器,运行时数据区(方法区,堆,虚拟机栈,本地方法栈,程序计数器),执行引擎(即使编译器,垃圾回收)组成

  • 方法区:线程共享,是常量池,静态变量以及方法信息(方法名、返回值、参数修饰符等)存储的地方;
  • 堆:线程共享,是虚拟机内存最大一块,存储是实例对象和数组;
  • 本地方法:线程不共享,调用本地方法,Java不能直接操作操作系统需要native修饰方法帮助;
  • 虚拟机栈:线程不共享,存储八大基本类型,局部变量,对象引用,实例方法;
  • 程序计数器:线程不共享,每个线程都会创建一个程序计数器保存正在执行的jvm指令,总是指向下一条被执行指令的地址;

3.堆栈区别?

  • 物理地址:堆的物理地址分配是不连续的,性能会慢些。栈是先进后出的原则,分配物理地址是连续的,性能快。
  • 内存:堆地址是不连续的,所以分配内存在运行期确认,大小不固定,堆大小一般远远大于栈。栈是连续的分配内存在编译期就确认,大小固定。
  • 内容:堆存放对象的实例和数组,该区关注数据存储;栈存放局部变量,操作数栈,返回结果,该区关注程序方法的执行。
  • 作用域:堆对于整个程序都是共享可见的;栈只对于线程可见,是线程私有的;栈的生命周期和线程相同。

4.有哪些类加载器?

引导类加载器(Bootstrap ClassLoader):jvm自带的加载器,负责加载java核心类库,该加载器无法直接获取。
拓展类加载器(Extension ClassLoader): 加载jre/lib/etc目录下的jar包。
系统类加载器(Application ClassLoader): 加载当前项目目录下的类或jar包,最常用的加载器。
自定义加载器(Custom ClassLoader): 开发人员自定义的。需要继承ClassLoader

5.类加载机制?

类加载过程是:加载,验证,准备,解析,初始化,使用,卸载。

  1. 加载;生成代表这个类的Class对象,作为这个类各个数据访问入口。
  2. 验证:确保代码符合Java虚拟机的规范标准。包括文件格式验证,元数据验证,指令验证,符号引用验证。
  3. 准备:为类中定义变量分配内存并设置初始值的阶段。
  4. 解析:是Java虚拟机将常量池内的符号替换为直接引用过程。
  5. 初始化:初始化阶段,Java虚拟机才真正开始执行类中编写的Java程序代码,将主导权移交给应用程序。本质上,初始化阶段就是执行类构造器的过程。并不是程序员在Java代码中直接编写的方法,它是Javac编译器的自动生成物。

6.双亲委派机制?

双亲委派过程:如果一个类加载器收到类加载的请求,首先自己不会尝试加载这个类而把这个请求委派给父类加载器去完成,所有的类加载请求都会传送给父类加载器。只有父类加载器无法完成加载,子加载器才会自己完成加载。
作用:避免类的重复加载:最终都会委派到顶端加载器。防止核心API被篡改:如果都让各个类加载器去加载的话,用户自己也编写一个Object类的话,系统中会出现多个不同的Object类,Java中最基础的方法也无法保证,就会混乱。

7.JVM垃圾回收算法有哪些?

一、什么对象是垃圾:一个对象长期不被引用或者不会被引用被称为垃圾。
二、如何判断是垃圾:
①引用计数法,被引用了数量加1没用了就减1为0就认为是垃圾;但是循环引用不会被其它引用但各自引用计数不为0.
②利用GCRoot算法(根可达)来判断是否是垃圾。jvm算出引用对象作为根GC root list往下发散,不引用和间接引用都是垃圾,和root没有关联和引用就是垃圾。根对象类型:a.虚拟机栈引用对象 b.方法区中静态属性引用对象。c.方法区常量引用对象 d.所以同步锁synchronized持有对象。
三、垃圾算法
1.标记-清除:标记有用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。
2.复制:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半,消耗内存。
3.标记-压缩:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
4.分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记压缩算法。
四、垃圾回收思想
分区思想:将堆分为很多小区间,回收根据小区间来回收,可以控制一次回收多少区间。

8.分代垃圾回收?

1.分代回收器有两个分区:老生代(2/3)和新生代(1/3),新生代使用的是复制算法,老生代:标记压缩算法。
2.新生代里有 3 个分区:Eden、To Survivor、From Survivor,默认占比是 8:1:1;
3.执行流程如下:
①把 Eden存活的对象放入From Survivor区
②From Survivor和To Survivor分区交换,From Survivor变To Survivor,To Survivor变From Survivor。

每次在转换移动时都存活的对象,年龄就 +1,当年龄到达15(默认配置是15:年龄存在对象头上,存储年龄是4位)时,升级为老生代。大对象也会直接进入老生代。老生代当空间占用到达某个值之后就会触发full垃圾收回,一般使用标记整理的执行算法。

9.jvm有哪些回收器?

新生代算法:标记复制算法;老生代算法:标记清除/压缩算法;整堆回收算法:分区算法。

  1. Serial(串行收集器):单线程,回收新生代,回收时会暂停工作线程直到收集结束(STW);Serial old:单线程回收老年代也会stw。适用于单cpu下的客户端模式 JDK5之前
  2. ParaNew(并行新生代收集器):是Serial的并行版本,也会STW。 -多cpu环境Server模式下CMS配合使用。 jdk8
  3. Parallel Scavenge(并行收集器):可控制高吞吐量,多线程回收新生代也会STW,比ParaNew好,可动态调整内存分配情况。Parallel Old(老年代并行收集器):Parallel Scavenge收集器的老年代版本。可控制高吞吐量,多线程并行回收老生代,回收时会STW。-多适用于后台运算不需要太多交互的场景
  4. CMS(并发标记清除收集器):停顿时间短低stw,实现垃圾收集线程和用户线程同时工作,多线程回收老生代。使用标记清除算法是为了保证清除时不影响用户工作线程。标记压缩算法引用对象地址会变。JDK8
  5. G1(垃圾优先收集器):并发,并行回收,低停顿,可控制并保证高吞吐量,作用于老生代和新生代,标记压缩和复制算法。

10.三色标记算法?

①STW:在标记垃圾的时候必须暂停程序,这样程序暂停会影响应用执行。1.为了解决问题使用三色标记算法并发标记,一边程序运行一边标记。2.避免重复扫描,提升效率。
②三色标记一些内容:三色标记也是利用可达性分析从GC Roots开始遍历,遍历中标记三种颜色。白色:对象没有标记过(垃圾)。灰色:该对象已被标记但是下属没有被完全标记。黑色:对象已被标记且下属也被全部标记(需要的对象)
③过程:1.初始状态都是白色然后从gc roots 开始出发 2.引用先标记灰色,没有引用还是白色。3.再次标记从灰色开始出发下属全部引用变为黑色,下属变为灰色。4.重复工作直到下属全部找完,没有引用还是白色就是垃圾。
④问题:1.浮动垃圾:因为一边标记一边运行,全部找完了,其中一个引用断开了没有引用了就会变成浮动垃圾。这种问题不大下一次GC回收就会处理掉。2.对象漏标:并发标记中,一个线程将一个白色对象断开成为垃圾对象,但另一个线程让黑色对象引用了该对象。重新标记不会从黑色开始找,就一直是白色会删除,这样会导致系统问题。cms对增加引用环节进行处理。G1对删除环节进行处理

11.cms垃圾回收器?G1垃圾回收器?

cms 回收器
介绍:cms是并发清除回收器,是实现用户线程和回收线程同时工作,低停顿的多线程回收老生代回收器。使用标记清除算法为了实现用户和回收线程同时工作,标记清除不会改变原来线程引用地址。
cms回收有四个步骤:
1.初始标记:单线程运行,需要stw,标记Gc roots能直达的对象。
2.并发标记:单线程,异步,无stw和用户线程同时运行,GC roots直达对象开始遍历。
3.重新标记:多线程,需要stw,标记并发阶段产生的垃圾对象
4.并发清除:单线程,异步,无stw,和用户线程同时运行,清理标记阶段要删除的对象。
优点:并发速度快,低停顿。缺点;占用线程拖慢速度,有内存碎片,因为是实现用户和回收线程同时运行所以不能等老生代满了再回收这对内存有较高要求。

G1 回收器
介绍:G1把连续的Java堆划分为多个大小相等区域,每个region都可以根据需要来扮演新生代的Eden空间,Survivor空间或者老年代空间。收集器能对扮演角色region采用不同策略去处理。优点:更精细控制,可预测停顿时间,优先处理,内存碎片控制。
过程:
1.初始标记:单线程运行,需要stw,标记Gc roots能直达的对象。
2.并发标记:单线程,异步,无stw和用户线程同时运行,GC roots直达对象开始遍历。
3.最终标记:多线程,需要stw,标记并发阶段产生的垃圾对象(标记范围小)
4.筛选回收:多线程,制定回收计划,选择多个region构成回收集,把回收集中region的存活对象复制到空的Region中再清理掉整个旧的region空间,需要stw

12.内存溢出和栈溢出?

内存溢出的原因: ①内存使用过多或者无法垃圾回收的内存过多,使运行需要的内存大于提供的内存。
         ②长期持有某些资源并且不释放,从而使资源不能及时释放,也称为内存泄漏。

栈溢出原因: 线程请求的栈容量大于分配的栈容量。

13.轻GC(minor GC)和重GC(full GC)?

一、轻GC,重GC
轻GC: 普通GC,当新对象在伊甸园区申请内存失败时,进行轻GC,会回收可回收对象,没有被回收的对象进入幸存区,新对象分配内存极大部分都是在伊甸园区,所以这个区GC比较频繁。一个对象经历15次GC,会进入老年区,可以设置。
重GC: 全局GC,对整个堆进行回收,所以要比轻GC慢,因此要减少重GC,我们所说的jvm调优,大部分都是针对重GC。
二、频繁minor GC:
①利用命令jstat -gc 进程ID 观察YGC和YGCT来判断,过于频繁就是了。 ②去观察Full GC(参数FGC和FGCT)是否正常,正常的话通常情况下就是新生代空间太小,频繁到老生代,可以通过配置改变新生代大小。
三、频繁Full GC:
①利用命令jstat -gc 进程ID 观察OC和OU使用情况,观察FGC和FGCT来判断。

14.什么时候出现重GC?

①当老年区满了会重GC:年轻区对象进入或创建大对象会满;
②永久代满了会重GC;
③方法区满了会重GC;
④system.gc()会重GC ;
⑤轻GC后,进入老年代的大小大于老年代的可用内存会,第一次轻GC进入老年代要2MB,第二次的时候会判断是否大于2MB,不满足就会重GC。

15.常用jvm参数?

• -Xms2g:初始化推大小为 2g;
• -Xmx2g:堆最大内存为 2g;
• -XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;
• -XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;
• –XX:+UseParNewGC:设置年轻代为并行收集,JKD5.0以上,JVM会根据系统配置自行设置,所以无需设置此值。
• -XX:+UseParallelOldGC:设置年老代为并行收集,JKD6.0出现的参数选项。
• -XX:+UseConcMarkSweepGC:指定使用 CMS垃圾回收器;
• -XX:+PrintGC:开启打印 gc 信息;
• -XX:+PrintGCDetails:打印 gc 详细信息。

  • 30
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值