Day05_JVM面试题

文章目录

说一下JVM的内存结构?

你只需要介绍一下它们内部存放了什么东西就行了。(比如虚拟机栈存放了。。。。)

JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈、直接内存六个部分,分别解释如下。

线程私有的:

  • 虚拟机栈:线程私有的,每个方法在执行时会创建一个栈帧,用来存储局部变量表、操作数栈、动态连接、方法返回地址等;其中局部变量表用于存放 8种基本数据类型(boolean、byte、char、short、int、float、long、double)和 reference类型。每个方法从调用到执行完毕对应一个栈帧在虚拟机栈中的入栈和出栈。
  • 本地方法栈:和虚拟机栈相似,本地方法栈是为虚拟机使用到的 Native 方法服务。
  • 程序计数器:线程私有的,在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

线程共享的:

  • 堆:线程共享的,在虚拟机启动时创建,用于存放对象实例。(石堆:堆里面存放实例对象)
  • 方法区:线程共享的,用于存储已被虚拟机加载的类信息、常量、静态变量等。(方法区存放不容易变动的信息),永久代是方法区的实现。
  • 直接内存:

在这里插入图片描述

说一下堆内存中对象的分配的基本策略

在这里插入图片描述
大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。

刚刚新建的对象在Eden中,经历一次 Minor GC,Eden中的存活对象就会被移动到第一块S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块S1中(这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生),每熬过一次Minor GC,年龄+1,若年龄超过一定限制,则被晋升到老年态。

大对象和长期存活的对象会直接进入老年代。为了避免为大对象分配内存时由于分配担保机制带来的复制而降低效率。( 分配担保机制就是eden满了,然后把新生代的大对象提前转移到老年代中去)

栈帧里面包含哪些东西?

局部变量表、操作数栈、动态连接、返回地址等

参考博文:https://blog.csdn.net/qq_35583772/article/details/90171153
在这里插入图片描述

程序计数器有什么作用?

线程私有的,在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

参考博文:Day1_JVM-内存结构

程序计数器为什么是私有的?

线程私有的,在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

所以,为了保证线程中的程序计数器不被别的线程访问到,它就是私有的。

(大白话:假如现在有一本书,有好几个同学都想看,我们采取这样的策略让所有同学都能看到:每个人看一天,不管看没看完都要交给下一个人看,不断循环,直到所有人看完。每个同学都有一个小卡片记录自己看到了哪里,这样下次轮到自己看的时候就能快速的接着上次看到的地方继续看。)

虚拟机栈和本地方法栈为什么是私有的?

  • 虚拟机栈:线程私有的,每个方法在执行时会创建一个栈帧,用来存储局部变量表、操作数栈、动态连接、方法返回地址等;其中局部变量表用于存放 8种基本数据类型(boolean、byte、char、short、int、float、long、double)和 reference类型。每个方法从调用到执行完毕对应一个栈帧在虚拟机栈中的入栈和出栈。
  • 本地方法栈:和虚拟机栈相似,本地方法栈是为虚拟机使用到的 Native 方法服务。

所以,为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的。

说一下堆

堆:线程共享的,在虚拟机启动时创建,用于存放对象实例。(石堆:堆里面存放实例对象)

Java 堆还可以细分为:新生代和老年代:再细致一点有:Eden 空间、From Survivor、To Survivor 空间等。进一步划分的目的是更好地回收内存,或者更快地分配内存。

这里是引用
在这里插入图片描述

字符串常量存放在哪个区域?

在这里插入图片描述

Java中的常量池分为三种类型:
1.字符串常量池,已经移动到堆上(jdk8之前是perm区)。
2.类文件常量池,constant_pool,是每个类每个接口所拥有的,这部分数据在方法区。
3.运行时常量池是在类加载后的一个内存区域,它们都在元空间。

在这里插入图片描述
在这里插入图片描述
为什么要把字符串常量池存放到堆里面?可能是为了多存储一些字符串吧

这篇文章还不赖,至少他的理解是对的: https://blog.csdn.net/zzzgd_666/article/details/87999870

你熟悉哪些垃圾收集算法?

引用计数法(被引用的对象就不清除,循环引用解决不了,所以被淘汰了)

标记清除(该算法分为“标记”和“清除”阶段:首先标记出所有不需要回收的对象,在标记完成后统一回收掉所有没有被标记的对象。问题是:会产生大量不连续的碎片

复制算法(它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。问题是:浪费空间

标记整理算法(首先标记出所有不需要回收的对象,在标记完成后不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。效率比前两者差

分代收集算法(老年代一般使用“标记-清除”、“标记-整理”算法,年轻代一般用复制算法。因为新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。)

HotSpot 为什么要分为新生代和老年代?

将 java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。

因为新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。

Java里有哪些引用类型?

强引用
Reference类以及继承派生的类,这种引用即使出现了OOM也不会对该对象进行回收,只有在和 GC Roots 断绝关系时,才会被消灭掉。

软引用
①对于只有软引用的对象来说,当系统内存充足时它不会被回收,当系统内存不足时它会被回收。
②可以看到,这种特性非常适合用在缓存技术上。比如网页缓存、图片缓存等。内存够用的时候就保留,不够用就回收!
③软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java 虚拟机就会把这个软引用加入到与之关联的引用队列中。

弱引用
对于只有弱引用的对象来说,只要垃圾回收机制一运行不管JVM的内存空间是否足够,都会回收该对象占用的内存。

虚引用
这是一种形同虚设的引用,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
虚引用必须和引用队列(ReferenceQueue)联合使用。
实际上,虚引用的 get,总是返回 null。

JVM怎么判断一个对象是不是要回收?

引用计数法(缺点是对于相互引用的对象,无法进行清除)

枚举根节点做可达性分析(根搜索路径)

如何判断一个常量是废弃常量 ?

运行时常量池主要回收的是废弃的常量。假如在常量池中存在字符串 “abc”,如果当前没有任何 String 对象引用该字符串常量的话,就说明常量 “abc” 就是废弃常量,如果这时发生内存回收的话而且有必要的话,“abc” 就会被系统清理出常量池。

如何判断一个类是无用的类?

方法区主要回收的是无用的类,判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面3个条件才能算是 “无用的类”ÿ

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘风破浪的牛马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值