自学内容网 自学内容网

JVM面试热点1

1.运行时数据区

线程共享:方法区、堆

线程独享:虚拟机栈、本地方法栈、程序计数器

2.程序计数器,是java虚拟机设计规范中的一个规定。if else、break等控制执行流程的地方。这是唯一一个没有OOM的地方,因为只记录一个行号。

3.java虚拟机栈:将方法的局部变量生成一个栈帧。

两种异常:请求的栈深度大于允许的栈深度。

  • 栈溢出(递归)

  • 有些jvm允许栈大小扩充,但是一直扩充电脑的内存也不够了就会产生OOM异常。(概率很小,电脑内存一般足够支持jvm的栈)

本地方法栈:如果java程序需要调用c程序,c程序不归jvm管了。但是java程序需要传参,交给虚拟机栈处理。很多虚拟机将本地方法栈和虚拟机栈合二为一。

  1. 堆,线程共享

    (1)考虑一个问题,线程共享,那堆的空间怎么分配?

    每个线程都有一个线程私有的分配缓存区,就是一块小空间,先让这个线程用着。

    堆逻辑上连续,物理地址可以不连续。堆可以设置成可以拓展的,有参数控制。内存不够,报错OOM。

5.方法区、线程共享

存放类信息、静态变量、常量的区域,可能会OOM

2.创建对象

(1)创建前就确定对象的大小,堆中怎么给对象分配空间?

指针碰撞:在用过的位置末尾之后移动一个空间,给新对象。适用于内存规整的。

空闲链表法:

(2)用上面的那个方法,垃圾收集器,是否带有垃圾整理的功能。

7.对象申请堆空间时,两个同时申请。并发异常?

(1)cas+失败重试

(2)tlab:每个线程在java堆中预先分配一小块内存,称为本地线程分配缓冲。本地缓冲用完了,分配新的缓存区采用同步锁定。

3.堆中对象存的结构

  • 对象头:使用标志位表现区分。类似100¥ 100$ 的区别。记录的信息包括:hash码、GC分代年龄、锁
  • 实例数据:类型指针、数组长度
  • 对齐填充:寻址必须是8字节的整数倍,这个填充是为了满足这个规定。

4.对象的访问定位

(1)句柄访问:
在这里插入图片描述

(2)直接指针(hotspot采用的这个)

在这里插入图片描述

优缺点

(1)对象移动时。句柄引用:在堆中内存发送变化。只需要修改句柄的指针地址就行。如果是直接引用,好几个对象都引用了堆中的实例,reference都需要修改。

(2)但是句柄引用在定位对象时,显然需要一个句柄媒介。速度比直接引用慢。

5.垃圾回收(针对堆和方法区)

那些内存需要回收、什么时候回收、怎么回收

(1)判断对象已死?

引用计数法:在对象头添加引用它的指针个数。问题是:循环引用。

可达性分析:(java、c#)所有对象以GCROOT为根,连接起来了就不用回收

(2)引用

  • 强:即使OOM也不回收
  • 软:内存溢出前回收
  • 弱:只要垃圾收集就死
  • 虚:对垃圾收集没关系,只有得到通知(插眼,也操作不了对象、只能看到它还活着)

类卸载需要将类加载器也回收

6.对象回收

(1)假说:

  • 弱分代假说:所有对象都是朝生夕灭
  • 强分代假说:(可能是GCROOT)活的越久就活的越久

(2)针对这些假说,将对象分类分区存储。弱分代,扫描高频。强分代,扫描低频。

  • 新生代:死的快的

  • 老年代:活的久的

(3)对象的跨代引用(老年代对象指向新生代对象)?

相互引用的对象,如果新生代也一直没被回收,也放到老年代。

(4)算法

标记清除算法:第一轮打标记,第二轮清除(效率不稳定、空间碎片化;只清除不填充)

标记复制算法:为了解决有大量可回收对象效率低的情况。将空间分成A和B两块区域。A用完了,将还存在的对象复制到B。(只利用一半空间,如果存活对象比较多,来回复制开销大)。新生代划分成:伊甸园8 幸存1 幸存1比例,每次例如90%的空间。问题是保证不了这10%能存下所有幸存的对象。解决:放不下的仍老年代。

标记整理算法:针对如果存活的对象很多,标记复制效率很低。第一轮先打标,第二轮将存活的移动到开头排好。移动对象时什么也不能干(stop the world)

分代算法:将对象分代存放,按照各自不同的特点选择合适的回收算法。


原文地址:https://blog.csdn.net/m0_63803244/article/details/140402791

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!