【每日一问之持续更新~~】

文章目录

一、MySQL数据库相关

1、什么是脏读?幻读?不可重复读?(230906)

1,脏读:当前执行的事务读取到其他事务修改或者新增数据库数据但未提交事务的数据。
2,幻读:当前执行的事务涉及的SQL语句不变,在不同时间段读取到数据数量不一致(读取到其他事务新增后的数据库数据)
3,不可重复读:当前执行的事务涉及的SQL不变,在不同时间段执行当前事务SQL,得到的数据结果是不一致,这主要体现在读取的数据是被其他事务修改或者删除后的最新数据,与第一次读取到的结果不同
注:不可重复读和幻读很相识,其两个的区别在于:不可重复读主要重点于读取到其他事务执行update和delete后的数据,而幻读重点于其他事务执行insert后的数据

参考答案: 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。 幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

2、什么是数据死锁?怎么解决?(230907)

数据库死锁指的是:当多个事物并发的去处理多个资源时,若双方已经锁定一部分资源,彼此一方想要往下执行的前提是需要对方已经锁定的资源时,这时就导致任何一方的事物在短时间内无法完全获取到所需要的资源数据,没有外力的作用就会处于一个无限期的等待状态,从而造成一种僵持状态,也就是死锁问题 解决数据库死锁问题,其实就先要分析死锁产生的必要条件: 第一个是:锁的互斥 第二个是:不可剥夺资源(就是说当前的进程已获得的资源,在末使用完之前,不能强行剥夺) 第三个是:请求资源与保持资源(当前进程因请求其他资源而导致阻塞时,对已获得的资源是保持不释放的) 第四个是:循环等待资源 那解决死锁的问题,只需要打破其中一个必要条件,其死锁就不成立: 例如:请求资源与保持资源,我们在程序中的业务逻辑就可以更改为:如果当前事物获得部分资源,但是得不其他资源,则就需要释放掉占用的资源, 再例如:我们可以让资源的请求分配变得有序,想要获取下一个资源,就先持有上一个资源,不持有上一资源的事物,不可分配其他资源 参考答案:死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。 常见的解决死锁的方法 a)如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。 b)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率; c)对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率; 如果业务处理不好可以用分布式事务锁或者使用乐观锁

3、解释下MVCC多版本并发控制机制(230908)

MVCC多版本并发空是数据库用来解决==>数据读操作与数据写操作冲突的无锁并发控制,也就是说读操作只能读取该事物开始前的数据快照(readView),在并发读数据时,可以做到不用阻塞写操作,写数据时,也可以做到不用阻塞读操作,从而提高了数据库的并发读写性能,除此之后,也解决了脏读、幻读、不可重复读的事物隔离问题,但是,有一点不好之处是不能解决更新数据丢失的问题

参考答案:Mysql在可重复读隔离级别下如何保证事务较高的隔离性,这个隔离性就是靠MVCC(Multi-Version Concurrency Control)机制来保证的,对一行数据的读和写两个操作默认是不会通过加锁互斥来保证隔离性,避免了频繁加锁互斥,而在串行化隔离级别为了保证较高的隔离性是通过将所有操作加锁互斥来实现的。,Mysql在读已提交和可重复读隔离级别下都实现了MVCC机制。 注意:多理解下课程里面“版本链比对规则”

4、BufferPool缓存淘汰机制是怎样的,推荐优化设置多大(230909)

Buffer Pool: 我们都知道,虽然MySQL的数据都是存在磁盘中的,但是也不能每次都从磁盘中去读取数据,这种与磁盘交互的过程性能是极差的,所以,MySQL内部就构建了一块数据缓存的内存区域=>Buffer Pool,是用来提高数据库的读写性能的,其默认的大小为128M,我们可以调节相关的buffer_pool_size来制定大小,一般推荐优化调整系数为:物理内存的百分之60到80之间; Buffer Pool的大小是有限的,如果需要保证其不会因为满了而导致无法缓存新的数据,可以使用LRU算法,其算法的实现思路是这样子的: 1、当访问的页(页类似B+树的一页,大小也是16KB,主要类型分为:空闲页、干净页和脏页)数据在buffer pool中时,我们就把当前的这一页数据移动到链表(LRU list)的头部(越靠近头部,就说明是近期常用的) 2、如果是当访问的页数据不在buffer pool中,除了要将当前页从磁盘中加载出来放到链表头部外,还需要把链表的尾部最后一个节点给淘汰掉 但是普通的LRU算法会带来几个问题:

1、MySQL的预读失效就是说MySQL在加载数据时,会提前将相邻的数据也一并加载进来,目的是为了减少磁盘IO,但是有可能加载进来的数据没有被访问到,这时候预读进来的数据就白做了,就称为预读失效=>解决方案是:MySQL内部类似JVM,LRU 划分了 2 个区域,分别是old区和young区,预读的页就只需要加入到 old 区域的头部,当页被真正访问的时候,才将页插入 young 区域的头部

2、buffer pool污染就是说当某条业务SQL语句扫描了大量的数据时,在buffer pool内存有限的情况下,可能会将里面所有的页数据都替换出去,从而导致大量的热点数据被淘汰了,等这些热点数据被访问时,由于在buffer pool缓存中没命中,只能到磁盘中获取,这时候就需要大量的磁盘IO,导致MySQL的性能急剧下降,这个过程我们就称为buffer pool污染,需要注意的是,buffer pool污染并不是说查询语句查询出大量的数据才会出现的问题,即使查询出来的结果集很小,也会出现,例如:如果在一张数据量非常大的表中执行like查询,且没命中索引情况下,那查询的整个过程是全表扫描的,那就需要将磁盘页数据逐个加入到buffer pool中===>解决方案:要想保证热点数据,我们就需要提高进入young区的门槛,MySQL是这样子做的,进入到young区域的条件增加了一个在old区停留的时间判断,具体为:在对某个处在 old 区域的缓存页进行第一次访问时,就在它对应的控制块中记录下来这个访问时间:
如果说后续的访问与第一次记录的时间在某个时间间隔范围内,就不能将其移到young区域,反之,不在间隔就可以移到young区头部位置,这个时间间隔是由innodb_old_blocks_time 控制的,默认是 1000 ms。也就是说,只有同时满足「被访问」并且「在 old 区域停留时间超过 1 秒」两个条件,才会被插入到 young 区域头部,这样就解决了 Buffer Pool 污染的问题 。

参考答案:主要使用了LRU算法 1.3/8的list信息是作为old list,这些信息是被驱逐的对象。 2.list的中点就是我们所谓的old list头部和new list尾部的连接点,相当于一个界限 3.新数据的读入首先会插入到old list的头部, 4.如果是old list的数据被访问到了,这个页信息就会变成new list,变成young page,就会将数据页信息移动到new sublist的头部。 5.在数据库的buffer pool里面,不管是new sublist还是old sublist的数据如果不会被访问到,最后都会被移动到list的尾部作为牺牲者 一般推荐BufferPool大小为机器物理内存的60%左右

5、解释下隔离级别与锁的关系(230910)

读未提交:事务读不会阻塞其事务的读和写,事务写会阻塞其他事务的写,但是不阻塞读,所以会产生脏读的情况,这样子的话,在这个隔离级别写的时候是加了一把读锁(S锁);
读已提交:事务读不会阻塞其他事务读,但会阻塞其他事务写,事务写的时候会阻塞其他事务读和写,这样子的话,在这个隔离级别写的时候是加了一把写锁(X锁),读的瞬间会加了一把读锁(S锁),读取完毕就会立马释放;
可重复读:相比读已提交的情况,加锁的不同点在于,可重复读在事务读的时候全程是加锁的,这样的话,在整个事务过程中,任何其它事务不能写,可以保证两次读到的数据是一致的
串行化:全程加的都是写锁的方式,不管是读还是写,都是直接给被操作的记录加写锁(X锁),实现了串行化。但是这样会让事务串行执行,但是会极大的降低并发性能。

参考答案:在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突 在Read Committed级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁; 在Repeatable Read级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁。 SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。

6、distinct使用临时表计算可以通过什么方式来优化(230911)

Distinct去重的字段,如果没有使用到索引,那此时的结果集会放入一个临时表中,然后在临时表中进行去重处理,效率较低; 优化的话,我们可以尽可能让去重的字段走索引,在扫描索引树的时候就完成去重 参考答案:对distinct字段加索引,这样查询结果在索引树里就能直接过滤重复的值

7、索引设计原则有哪些(230912)

1、主体业务代码先确定后,再将代码中涉及的SQL进行分析,再逐步确认索引的字段 2、小基数列的字段不应作为索引列,例如:大部分业务场景下的信息有效性字段列,不同值就只有“是”和“否” 3、在日常业务中,频繁作为where查询条件的字段,也就是索引尽可能覆盖大多数的查询条件 4、还有distinct字段去重的字段,也尽可能设计索引 5、多表连接时候,连接字段应该尽量让其走索引,不走索引的会导致其连接方式的底层算法为基于块的嵌套循环连接算法,效率极低 6、字段列的字符长度如果过于长,可以采用字符前缀方式作为索引

参考答案:
a)代码先行,索引后上
b)联合索引尽量覆盖条件
c)不要在小基数字段上建立索引
d)长字符串我们可以采用前缀索引
e)where与order by冲突时优先where
f)基于慢sql查询做优化

8、常用的Order by与Group by如何优化(230913)

涉及order by的SQL,优化时候,应注意order by的字段是否是索引字段,如果不是索引字段,应结合业务需要,考虑排序字段添加索引或者换其他字段进行排序,如果是联合索引,where条件+order by使用联合索引的顺序需要满足索引的最左前缀的顺序,才能使得排序操作在索引树中完成排序,不然执行计划的Extra列会出现filesort(文件排序,分为单路排序和双路排序)情况,效率极低; group by和order by很类似,因为group by 是先排序再分组,优化原则也是同order by方案类似

参考答案:
a)如果order by的条件不在索引列上,就会产生Using filesort,尽量对order by的字段建立索引
b)能用覆盖索引尽量用覆盖索引
c)对于group by的优化如果不需要排序的可以加上order by null禁止排序

9、分页查询如何高效优化?(230914)

1、如果索引字段是有序的自增场景=>我们可以利用ID限定方法来优化,也就是将索引作为查询的条件,例:select * from xx where xx索引 > yy limit z; 2、若是其场景的,以下列举两种优化方式; 2.1、其他场景,我们可以通过子语句方式来优化,使子语句结合业务需求,命中索引,让其查出id与外层的查询语句进行表连接查询; 2.2、除在SQL中做优化,我们可以使用一些中间件进行数据优化,例如,Redis缓存、ES搜索引擎等

参考答案:
a)根据自增且连续的主键排序的分页查询,可以先用范围查找再用limit
b)根据非主键字段排序的分页查询,非主键字段先建索引,然后先用非主键字段排序再查出主键id,再用主键id查出最终结果

10、InooDB和MyISAM的select count(*)哪个更快,为什么?(230915)

myisam存储引擎会快些,因为myisam对数据总行数有专门维护,而innodb存储引擎没有维护,需要去统计

参考答案:
myisam更快,因为myisam内部维护了一个计数器,可以直接调取。

11、mysql行锁所升级为表锁的原因有哪些(230916)

InnoDB存储引擎中,行锁升级为表锁的情况如下: 1、当修改数据时,如果传入的数据类型与表的修改列数据类型不一致,这时候MySQL的内部优化器需要做类型的强制转换,会由行锁上升为表锁; 2、因为行锁锁的是这行的索引,那如果数据行加锁时,没有索引,这时,行锁也会上升为表锁;

参考答案:
MySQL 的行锁(Row Locks)在某些情况下可能会升级为表锁(Table Locks),这通常是因为以下原因:
锁粒度升级:MySQL 的存储引擎会根据需要升级锁的粒度,以确保数据的一致性和并发性。如果多个事务同时请求对同一行的锁,而且这些锁请求无法同时被满足,系统可能会将锁的粒度升级为表级别,以避免死锁和维护数据的一致性。
长事务:如果一个事务持有一个行级锁,并且该事务长时间运行,其他事务可能需要等待太长时间才能获取该行的锁。为了避免长时间的等待,系统可能会升级锁的粒度,以释放行级锁,并允许其他事务访问表中的其他行。
锁冲突:如果多个事务在表中的不同行上请求锁,并且这些锁请求发生冲突,例如,一个事务要求共享锁,而另一个事务要求排它锁,系统可能会将锁的粒度升级为表级别,以解决冲突。
存储引擎限制:某些存储引擎在某些情况下可能不支持行级锁,或者不支持在某些特定条件下使用行级锁。在这种情况下,存储引擎可能会将锁升级为表级别。
锁超时:如果一个事务在一定时间内无法获取到所需的行级锁,系统可能会将锁升级为表级别,以确保事务可以继续进行,而不会一直等待。

12、为什么使用数据索引能提高效率(230917)

因为使用数据的索引后,一方面是会大大减少对磁盘的IO次数,另一方面是索引选择的数据结构,也会很快的找到满足条件的索引值

参考答案:
数据索引的存储是有序的
在有序的情况下,通过索引查询一个数据是无需遍历索引记录的
极端情况下,数据索引的查询效率为二分法查询效率,趋近于 log2(N)

13、mysql为什么用自增列作为主键或者其他顺序ID(230918)

首先是因为用自增的作为主键,数据类型为数字类型(一般为int类型),占用的内存空间较小,其次是因为索引树在构建时,需要对索引值进行排序,如果数据类型是数字的,那排序的性能相比其他类型会快很多,而且查找数据时,索引值是数据类型的,比较时,相比其他类型的,会快些

参考答案:
1、如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引。
如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引。
如果也没有这样的唯一索引,则InnoDB会选择内置6字节长的ROWID作为隐含的聚集索引(ROWID随着行记录的写入而主键递增,这个ROWID不像ORACLE的ROWID那样可引用,是隐含的)。

2、数据记录本身被存于主索引(一颗B+Tree)的叶子节点上,这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点) 3、如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页 4、如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置,此时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。

14、什么情况下应不建或少建索引(230919)

1、经常更新的字段 2、重复值较多的字段 3、不同值的基数较小字段 4、不经常查询的字段 5、数据量较小的数据表

参考答案:
1、表记录太少
2、经常插入、删除、修改的表
3、数据重复且分布平均的表字段,假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。
4、经常和主字段一块查询但主字段索引值比较多的表字段

15、分表有什么好处?以及分区有什么好处?(230920)

1、可以均衡系统的IO:因为可以把不同的分区映射到不同的操盘上,起到一个改善整个系统性能的作用 2、改善查询性能:对分区查询的对象,可以仅搜索自己关心的分区,提高检索的效率 3、维护方便且高可用:如果表的某个分区出现问题,那只需要对某个分区进行修复,不影响其他分区表的使用,这也是体现高可用的一种方式

参考答案:
分表:指的是通过一定规则,将一张表分解成多张不同的表。比如将用户订单记录根据时间成多个表。
分表与分区的区别在于:分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表。
1、存储更多数据。分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。和单个磁盘或者文件系统相比,可以存储更多数据
2、优化查询。在where语句中包含分区条件时,可以只扫描一个或多个分区表来提高查询效率;涉及sum和count语句时,也可以在多个分区上并行处理,最后汇总结果。
3、分区表更容易维护。例如:想批量删除大量数据可以清除整个分区。
4、避免某些特殊的瓶颈,例如InnoDB的单个索引的互斥访问,ext3问价你系统的inode锁竞争等。

15、解释下双亲委派机制以及为什么要设计双亲委派机制?(230921)

在java中,类加载主要分为:自定义类加载器、AppClassLoader、ExtClassLoader、BootStrapClassLoader 在加载类资源到JVM时,当前类加载器会先判断在已加载过的列表中是否存在,如果不存在,当前的类加载器会委派自己的parent类加载器进行加载,如果父加载类都没有加载到当前类资源,就由当前的类加载器进行加载 设置这个机制一方面是因为考虑到沙箱安全机制,例如java中的一些核心内库中的类,是不允许被随意撰改的,另一方面是为了让类不被重复性加载,父类以及有的类,当前类加载器都不用再加载一次了

参考答案:
a)双亲委派机制加载某个类时会先委托父加载器寻找目标类,找不到再委托上层父加载器加载,如果所有父加载器在自己的加载类路径下都找不到目标类,则在自己的类加载路径中查找并载入目标类。
b)双亲委派机制可以实现沙箱安全机制与避免类的重复加载

16、Tomcat 如果使用默认的双亲委派类加载机制行不行,为什么?(230922)

不可以,因为Tomcat在部署服务时,需要兼容同一个包下不同版本的应用程序类,例如Spring不同版本的应用程序,都需要支持,如果只使用默认的双亲委派机制不能解决上述问题 Tomcat内部通过打破双亲委派机制来解决,属于spring内部的,就由自定义加载类加载,反之由双亲委派机制加载

参考答案:
如果使用默认的类加载器机制,那么是无法加载两个相同类库的不同版本的,默认的类加器是不管你是什么版本的,只在乎你的全限定类名,并且只有一份。

17、说一下 JVM 的主要组成部分及其作用(230923)

JVM优化,其实原则上就是需要降低fullGc次数频率,降低系统的延迟带来不好的用户体验,让大部分朝生夕死的对象尽可能在新生代就被回收掉 通常优化主要分为程序方面和jvm内存分配情况方面,我们需要结合业务场景以及大体的对象大小、Gc时长和频率,估计出对象在jvm中的流转模型图,结合实际问题进行逐层剖析

参考答案:
JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。
Class loader(类装载):根据给定的全限定名类名(如:java.lang.Object)来装载class文件到Runtime data area中的method area。
Execution engine(执行引擎):执行classes中的指令。
Native Interface(本地接口):与native libraries交互,是其它编程语言交互的接口。
Runtime data area(运行时数据区域):这就是我们常说的JVM的内存。
作用 :首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。

18、jvm优化原则是什么(230924)

参考答案:
尽可能让对象都在新生代里分配和回收,尽量别让太多对象频繁进入老年代,避免频繁对老年代进行垃圾回收,同时给系统充足的内存大小,避免新生代频繁的进行垃圾回收

19、讲下对象创建的流程(230925)

创建对象时,先判断对象是否被加载过 如果加载过:进行内存分配, 没有加载过:先加载类,再分配内存 分配内存时候:主要有两种方式,分别是指针碰撞和空闲列表方式进行内存分配,且会进行对象是否为逃逸对象分析,分析结果会决定对象分配在堆还是栈中 分配完内存之后,就会进行初始化,初始化过程,其实就是给分配的内存空间都初始化为零值 初始化完毕之后,就开始设置对象头 设置完对象头后,就执行init方法,就是属性赋值,以及执行构造方法,对象就完成创建

参考答案:
a)类加载检查
b)分配内存
c)初始化零值
d)设置对象头
e)执行方法

20、解释下对象栈上分配(230926)

JVM在给对象分配内存时,会先对该对象进行逃逸分析, 逃逸分析其实就是分析当前方法中,创建该对象时,是否会以该对象作为方法的返回值方式返回,如果没返回,就说明该对象不是逃逸对象,就将该对象分配到栈内存中,随着方法的结束而结束,反之为逃逸对象,就会分配到堆中 分配到栈内存中的方式主要有标量替换,目的是为了解决栈内存中连续空间不足于存储对象缺陷,所以JVM中就会将该对象的成员变量拆分成若干个被指定引用的成员变量分别存到栈中,就无需要求连续内存存储

参考答案:
我们通过JVM内存分配可以知道JAVA中的对象都是在堆上进行分配,当对象没有被引用的时候,需要依靠GC进行回收内存,如果对象数量较多的时候,会给GC带来较大压力,也间接影响了应用的性能。为了减少临时对象在堆内分配的数量,JVM通过逃逸分析确定该对象不会被外部访问。如果不会逃逸可以将该对象在栈上分配内存,这样该对象所占用的内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力。
对象逃逸分析:就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中。

21、class文件内部结构组成(230927)

1、魔数 2、class文件版本 3、常量池 4、访问标志 5、类索引,父类索引,接口索引集合 6、字段表集合 7、方法表集合 8、属性表集合

参考答案:
class字节码文件由魔数,主次版本号,常量池,类信息,类的构造方法,类的中的方法信息,类变量与成员变量等信息组成

22、说下常量池类型分类(230928)

1、静态常量池:存放编译之后生成的字面量和符号引用 2、运行时常量池:在类加载后会将静态常量池中的内容存放到方法区运行时候常量池中 3、字符串常量池:针对String类型对象,如果是第一次创建的,除了在堆中创建出一个对象,还会在字符串常量池中也创建一份,目的是为了使JVM能在一定程度下提高性能和减少内存开销

参考答案:
按类型分为字面量、符号引用类型
字面量分:
CONSTANT_Utf8_info: utf8字符串
CONSTANT_Integer_info 整型字面量
CONSTANT_Float_info 浮点型字面量
CONSTANT_Long_info 长整型字面量
CONSTANT_Double_info 双精度字面量
符号引用类型分:
CONSTANT_Class_info:表示类或接口
CONSTANT_String_info:String类型的常量对象
CONSTANT_Fieldref_info:字段信息表
CONSTANT_Methodref_info:方法
CONSTANT_NameAndType_info:名称和类型表
CONSTANT_InterfaceMethodref_info:表示接口方法符号引用
CONSTANT_MethodType_info:方法类型表
CONSTANT_MethodHandle_info: 方法句柄表
CONSTANT_InvokeDynamic_info:动态方法调用点

22、说一下 JVM 运行时数据区(230929)

JVM运行时数据区指的是:JVM在运行时分配的内存区域,其主要包括以下几个部分组成: 1、程序计数器 2、Java虚拟机栈 3、本地方法栈 4、Java堆 5、方法区

参考答案:
不同虚拟机的运行时数据区可能略微有所不同,但都会遵从 Java 虚拟机规范, Java 虚拟机规范规定的区域分为以下 5 个部分:
1.程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成;
2.Java 虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作数栈、动态链接、方法出口等信息;
3.本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;
4.Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存;
5.方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。

23、说一下 JVM 有哪些垃圾回收算法(230930)

1、标记-复制算法 2、标记-清除算法 3、标记-整理算法

参考答案:
标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。
复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。
标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。

23、 解释浮动垃圾是怎么回事(231001)

浮动垃圾主要表示本来应该是需要回收的垃圾,但是在本次GC没有被回收,产生这种情况的原因主要是: 例:在CMS垃圾回收器的并发标记和并发清理过程中,垃圾回收线程与用户线程是一起进行的,那就不能排除,在标记和回收的过程中,各对象的引用关系都有可能会发生变化,有可能产生新的垃圾对象且不参与本次的GC,只能是下一次触发GC后再参与重新扫描和回收操作

参考答案:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值