哦虎!头像

【JavaEE进阶】JVM(面试)

jvm就是JAVA虚拟机,这个和我们软件虚拟机vmware不一样,他只是针对JAVA程序,针对字节码进行解释执行
像python JavaScript都是需要虚拟机的编程语言,为的是更好支持不同操作系统和CPU

jdk是JAVA开发工具包
jre是JAVA运行环境
jvm是JAVA虚拟机

它们一层包一层
开发JAVA代码,安装jdk就包含了jre
不需要开发就只运行了一个JAVA程序,只安装jre即可

jvm很多底层东西,和我们关系不大,主要是高频面试题

一、jvm内存区域划分

每次运行JAVA程序的必然就创建了对应的JVM,JAVA中使用的内存其实就是JVM内存。JVM内存是启动的时候,从操作系统申请的,应用程序后续需要使用的时候就可以从JVM内存进行分配

不同区域

1.程序计数器

很小的区域只保留数字,也就是下一条要执行JAVA字节码指令的地址,在内存中,通过软件维护

2.栈

面试的时候被问到那个啥是战和队,我们要反问是哪个栈哪个堆?是数据结构的,还是JVM的,还是操作系统?

分成虚拟机栈,本地方法站

  1. 虚拟机栈

放局部变量

给JAVA程序使用的栈,维护了方法调用关系

每调用一个方法,就会有一个栈帧(frame
里边放
调用方法的实参
方法内部的局部变量
方法结束后又返回的上层方块的位置
还有返回值

完事一个删掉一个,后进先出

  1. 本地方法栈

给C加加代码使用的JVM底层是C加加实现的
放native本地方法的栈帧

3.堆

内存最大区域

存放new的对象,还有普通成员变量

4.元数据区

之前称之为方法区

放类对象,还有static修饰的成员
用static修饰的属性就变成类属性,而不是实例属性了
实力属性是跟着对象走的,类属性是跟着类走的

给一段代码,问,其中的变量都是属于哪个内存区域中的?


二、内存溢出

1.栈溢出

栈里面包含了方法的调用关系,栈帧太多了,一般都是递归导致的

2.堆溢出

new的对象太多了,无限循环往集合中添加元素


以上内存区域
针对程序计数器和栈,存在多份的(每个线程有一份自己的)
堆和元数据区一个进程中只有一份了~
一个线程中new对象,是可以直接被另一个线程使用的~~


三、JVM类加载机制

类加载就是.class文件读取到内存中,构造出类对象过程

触发这个

  1. 创建实例
  2. 使用静态方法或者静态属性
  3. 使用子类影响到父类

1.类加载流程

(1)加载

把.class文件找到,打开文件,并且读取文件的数据到内存中

怎么找到?
JAVA代码中,要使用到某个类,需要import,后面跟着全限定类名,把代码中写的权限定类名,找到对应的点class文件

(2)验证

根据读到的二进制内容,检验是合法的格式

(3)准备

给要创建的类对象分配内存空间

从元数据区安排一块内存保存这里的类对象,JAVA默认把新申请的,未初始化的内存全都设为0,尝试获取static抽在你身边

(4)解析

针对字符串常量进行初始化

需要把当前.class中的字符串常量也放到内存中
此时字符串就有了起始地址,顺便可以把这些地址取出来,放到对应使用字符串的地方

(5)初始化

针对类对象进行初始化,
涉及到初始化的静态成员,执行静态代码块,对父类的加载


以上五个步骤背下来


什么时机加载某个类?

懒汉思想用到的时候才加载

  1. new一个类的实例
  2. 调用这个类的静态方法/访问静态成员
  3. 针对子类的加载也会触发父类的加载

类加载加载一次即可,每个类的对象在一个JVM进程中也是单例的


2.双亲委派模型

双亲委派模型用来找.class文件,
涉及到一个模块,成为类加载器,JVM中默认包含三个类加载器

  1. BootstrapClassLoader
  2. ExtensiohClassLoader
  3. ApplicationClassLoader
    父子关系(不是父类子类
    这个类加载器中有一个parent这样的属性,指向父亲的引用
    从下往上指向父亲,类似于链式结构BootstrapClassLoader,负责加载JAVA标准库中的类
    ExtensiohClassLoader ,负责加载JAVA扩展库中的类(jdk厂商做出的扩展,现在已经很少使用
    ApplicationClassLoader,负责加载第三方库以及你当前项目中的类

一,标准类加载步骤
1)把全限定类名,交给ApplicationClassLoader
2) ApplicationClassloader把任务转交给父亲进行处理
3)ExtensionClassLoader还是把任务转交给父亲进行处理
4) BootstrapClassLoader没有父亲,只能自己处理.负责扫描指定的标准库类的目录,查找这个类
发现能够找到,因此就可以打开对应的.class文件读取文件,进行解析=>类加载的后续步骤~~

二,加载第三方
1)把全限定类名,交给ApplicationClassLoader
2) ApplicationClassLoader 把任务转交给父亲进行处理
3) ExtensionClassLoader还是把任务转交给父亲进行处理
4) BootstrapClassLoader没有父亲,只能自己处理.标准库中,找不到对应的类因此就把任务转交给孩子
5) ExtensionClassLoader 查询自己负责的目录发现也没有,继续把任务交给孩子
6) ApplicationClassLoader 查询第三方库的目录/当前项目的目录找到了就可以打开文件,读取文件如果在这一级还没有找到,抛出异常~~


本质上,双亲委派模型,约定了“类加载的优先级“标准库最先加载其次是扩展库最后才是第三方库/当前项目


垃圾回收GC

应对内存泄露

jvm专门指派一些线程,这些线程周期的扫描,你的代码已经申请的内存自动判定是否不再使用

1.找出谁是垃圾

在JAVA中,使用对象只有一种方式,就是通过引用的方式看某个对象是否引有引用指向,如果没有,就认为这个对象不再使用了,是垃圾回收

怎么判断有没有引用指向?

谈一谈JAVA的垃圾回收机制,就可以不谈应用技术,因为这是python和PHP的方案,如果是问谈一谈垃圾回收机制,就可以谈一下引用计数
第一种方案引用计数

你就是判断对方是不是垃圾

  1. 引用计数
    给每个对象身上安排一个空间,这个空间存储一个整数,表示指向对象引用的个数
    围绕对象进行引用赋值,就会更新这个数,如果计数是0就可以释放

但是有两个缺点,也是因为这两个缺点JAVA没有引用

(1消耗更多内存空间
如果计数器使用两个字节的,整个对象本来只有四个自己,这就占了50%了
(2产生循环引用会导致出现误判
微信

  1. 可达性分析

微信

通过可达性分析的方式,从所有GCRoots出发,尽可能遍历,访问到的对象都标记可达,剩下的就是不可达

一棵树有很多个根GCRoots构成
GCRoots有哪些

1 栈上的局部变量

栈有很多,每个栈栈帧也很多,每个栈帧中局部变量也有很多

2 常量池引用指向对象

字符串常量String也有一系列引用类型成员,至少有一个 byte[]
Integer值JVM把-128=>+127这个范围的数字提前创建好Integer 对象

3.所有的引用类型静态成员

好的地方
可达性分析,没有引入额外的内存空间
没有循环引用的问题

弊端
可达性分析的问题,需要消耗更多cpu资源/更多时间
这就是c加加不愿意引入gc的原因

识别出垃圾之后,如何释放内存
1。标记清除
把标记出来的垃圾,直接释放掉
但是对象是垃圾,随机的,可能会在频繁示范中出现大量的内存碎片,被释放的内存在地址上是离散的(不连续)申请内存都是连续内存,总空闲空间充足,尝试申请大块内存,申请失败

2。复制算法
有效解决内存碎片问题
使用内存空间的一般,把不是垃圾的对象复制到另一半
缺点 空间利用率低
如果当前存活的对象多,复制开销大
3。标记整理
对于空间利用率,得到了改善
类似于顺序表删除中间元素,也就是搬运
把存货的数据放到非存活的数据位置,开销同样可能很大

对于JAVA实际情况,综合上述策略,构成了一个更复杂的方案

4。分代回收,根据不同对象的特点,采取不同的方安
引入对象年龄,如果对象年龄比较大,有很大概率继续存活下去,GC扫描轮次是周期性进行的,经过很多轮都没有被释放,说明年龄比较大

分为两个大部分
新生代和老年代
新生代分为伊甸区和幸存区
伊甸区放刚创建的对象,经过第一轮GC的时候,把大部分淘汰掉
经过GC没有淘汰的对象同过复制算法进入幸存区
幸存区有两个部分,每次只用其中一个部分
下一轮GC也会针对幸存区进行扫描,淘汰掉一大批对象,通过复制算法,进入到另一个幸存区

每一轮GC淘汰很多,因此出发复制的对象少,解决了复制算法拷贝开销大的问题
另一面,幸存区只占新生代10百分之,浪费内存空间小

针对老年代的扫描,称为 Major GC 开销大,频率低
针对新生代的扫描,称为 Minor GC 开销小,频率高
这两者整体称为 FulI GC

4.随着每一轮GC的进行,对象就会在新生代的幸存区来回拷贝没经过一次拷贝,对象的年龄就+
5.经过一定时间之后,对象的年龄达到一定的阈值,此时就会把这个对象拷贝到老年代
6.对象进入老年代之后,针对老年代的GC频率比新生代低很多了.减少了扫描的开销

如果是某个对象占据内存很大的,直接进入老年代

老年代发现对象是垃圾,采取标记整理的方式处理
虽然整理一次,比较消耗资源的 但频率比较低

OK了,再见

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2601_95402431/article/details/167037742

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--