java架构师成长之路
2021-07-13 20:35:18 0 举报
AI智能生成
java架构师成长之路
作者其他创作
大纲/内容
分布式
dubbo实现原理是什么?
redis
zookeeper
kafka
mq
es
高并发
jvm
内存模型是什么?
类加载子系统加载字节码文件过程?
加载
在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等等,在加载阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
验证
验证字节码文件的格式是否准确
准备
给类的静态变量分配内存,并赋予默认值
解析
将符号引用替换为直接引用,该阶段会把一些静态方法(符号引用,比如main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接引用
初始化
对类的静态变量初始化为指定的值,执行静态代码块
双亲委派机制原理是什么?
自定义一个类,先通过应用程序类加载子系统加载这个类,加载不到,则由其父亲扩展类子系统加载,再加载不到,则由引导类子系统进行加载,再加载不到,则继续依次从扩展类子系统加载
分代收集理论讲一下
程序创建对象后,new出来的对象会先进入堆中的新生代的eden区,当eden满了,则会出发minor gc进行垃圾回收
,绝大多数的垃圾对象会被回收掉,少数的对象会进入幸存区s0/s1,待下次minor gc时,如果仍然有垃圾对象,则会将s0的对象复制到s1,每次minor gc,幸存区存活的对象年龄会增加1,当对象年龄达到15时,则会进入老年代,周而复始,当老年代被这些回收不掉的对象占满或者触发了fullgc临界点时,则会出发fullgc
,绝大多数的垃圾对象会被回收掉,少数的对象会进入幸存区s0/s1,待下次minor gc时,如果仍然有垃圾对象,则会将s0的对象复制到s1,每次minor gc,幸存区存活的对象年龄会增加1,当对象年龄达到15时,则会进入老年代,周而复始,当老年代被这些回收不掉的对象占满或者触发了fullgc临界点时,则会出发fullgc
为什么jvm要性能调优?
有限的空间进行无尽的想象,减少fullgc的次数,尽可能的减少stw时刻,给用户造成不好的体验
如何计算对象的大小?
对象内存布局
一:Mark Word
32位机器,4B
64位机器,8B
二:类型指针
指针压缩
开启(默认)
4B
关闭
8B
三:数组长度
4B
四:实例数据
boolen1B
byte2B
short4B
int4B
long8B
char2B
float8B
double8B
引用
byte2B
short4B
int4B
long8B
char2B
float8B
double8B
引用
五:对齐填充
当对象大小没有和8B对齐时,会填充为8的倍数
如何计算对象大小呢?
https://www.processon.com/view/link/60ed56a707912906d9fdd88d
垃圾收集器有几种?讲一下各自优缺点
一:serial 串行收集器,老版本
缺点:垃圾回收时,使用单GC线程回收垃圾对象,暂停用户线程,stw时间比较长,用户体验差
优点:垃圾回收时,由于暂停了用户线程,只专注垃圾回收过程,没有多余的浮动垃圾之类的问题,简单而高效
新生代采用的算法是复制算法,老年代采用的是标记整理算法
二:Parallel Scavenge和Parallel Old并行收集器,1.8默认的收集器
优点:相对于串行收集器,唯一不同的是暂停用户线程后,使用的是多的GC线程进行垃圾回收,吞吐量优先
新生代采用的算法是复制算法,老年代采用的是标记整理算法
三:ParNew和CMS
ParNew基本上和Parallel收集器类似,唯一不同的是它可以和CMS一起使用
CMS
跨时代的垃圾收集器
最大特点:并行收集和低停顿
用户线程和GC线程并行运行,一边进行垃圾回收,一边运行用户线程
用户对停顿时间的感知很小,用户体验好
用户对停顿时间的感知很小,用户体验好
新生代采用的是复制算法,老年代采用的是标记清除算法
老年代CMS垃圾回收的过程
一:初始标记
标记gc roots直接引用的对象,速度很快,几乎感觉不到,暂停用户线程,有短暂的stw时刻
二:并发标记
用户线程和GC线程并行运行,一边用户线程产生的新的存活对象,一边GC线程标记那些存活对象,从GCRoots的直接关联对象开始遍历整个对象图的过程,耗时较长,那些已经标记过的对象状态会发生变化,比如错标、漏标问题
三:重新标记
由于并发标记时,一边产生新的存活对象,一边标记那些存活对象,这个过程是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,会有stw时间,比初始标记停顿时间稍长,远比并发标记时间短,重新标记主要采用了三色标记中的增量更新和写屏障解决错标和漏标问题
四:并发清理
用户线程和GC线程同时运行,开始清理那些垃圾对象,如果这段期间有新的对象产生,则标记为黑色不予处理
五:并发重置
重置本次gc的标记数据
缺点
一:多个gc线程和用户线程同时运行,会和CPU抢资源
二:并发标记和并发清理时,由于GC线程和用户线程同时在运行,会产生浮动垃圾,之前标记为存活对象,后来变为垃圾对象了,只能等待下一次GC清理
三:标记清除垃圾对象时采用的是标记清除算法,会产生大量的内存空间碎片,当然可以设置参数-XX:+UseCMSCompactAtFullCollection,可以在清除完之后进行整理,还可以控制多少次fullgc后,整理一次空间碎片
四:由于并发标记和并发清理阶段,一边用户程序运行,一边垃圾回收,可能造成上一次垃圾回收还没结束,再次出发fullgc,比如正在fullgc垃圾回收阶段,突然有大的对象进入老年代,直接占满,触发了新的fullgc,则会出现并发失败concurrent mode failure,这种情况只能用serial old来暂停所有用户线程,单线程进行垃圾回收
四:G1
低停顿,可以预测的停顿时间
五:ZGC
六:Epslion
七:sheandoah
G1的加强版,可以实现并发收集
CMS和G1垃圾收集器的异同
相同
一:初始标记、并发标记、重新(最终)标记阶段相同
二:都是低停顿
不同
一:CMS采用的是标记清除算法,会产生大量的空间碎片;G1采用的复制算法
二:G1在最终标记后面的阶段是筛选回收(短暂的stw),即先会对要回收的region中的对象大小进行价值评估和成本排序,然后再根据预定的回收计划预测停顿时间来进行回收垃圾对象,-XX:+MaxGCPauseMills,用户可以控制垃圾回收时间,可预测的停顿时间
三:G1中将内存分为多个大小相等的region,每个region大小为堆内存/2048,比如堆内存为4G,则每个region大小为2M,另外之前的分代概念由物理变为逻辑上的分代,eden、old,幸存区会分布在region中,另外还有个存放大对象的区域Humongous,当存活对象的大小大于region大小的50%,则会直接进入大对象region,eden和幸存区的比例仍然是8:1:1,但新生代的比例只会占堆内存的5%,即堆内存为4G,则新生代为200M
讲一下G1垃圾收集器的流程
吞吐量和响应快优先的垃圾收集器有哪些
常见的垃圾回收算法有哪些?讲一下各自的特点和优缺点
标记清除算法
标记那些存活的对象,然后回收那些垃圾对象,原来的内存空间不做整理,会产生大量的空间碎片以及如果要标记的存活对象过多,会很耗时间
标记整理算法
标记那些存活的对象,然后回收掉垃圾对象,并且重新对内存空间进行整理
标记复制算法(速度较快)
将内存分为两块,当这一块内存用完后,则将存活的对象复制到另一块中,然后清理前面已经使用的那块内存,垃圾回收只回收一块内存
性能调优有什么原则吗?
尽可能不让对象超过幸存区内存大小的50%,减少对象进入老年代
string涉及到的常量池常见面试题
常量和常量拼接,结果只有一个对象,字符串常量池中
常量和变量拼接,结果返回的是对象的引用,只有一个对象,变量拼接就相当于new
new String()有几个对象,两个对象,一个在堆中,一个在字符串常量池中,返回的是堆中的引用
new String()+new String(),总共6个对象
两个堆中的对象,一个StringBuilder,两个各自的常量池中的对象,一个new String('ab')
字符串常量池
如何快速定位CPU飙升100%问题?
一:top命令查看内存占用情况,查出占用cpu过高的进程id
二:H找出占用cpu内存过高的线程id
三:找到最高的线程id后转换为16进制
四:通过jstack 线程id|grep -A 10 进程id,找出占用cpu最高的调用方法
内存泄漏和内存溢出的区别
内存溢出
垃圾回收的速度小于内存分配的速度
内存泄漏
老年代的存活对象回收不掉,最终fullgc
如何判断一个对象是否为垃圾对象?
引用计数法
GC Roots可达性分析算法
什么对象会进入老年代?
一:长期存活的对象
分代年龄达到15或者CMS的年龄达到6时的对象会进入老年代
二:如果对象年龄从1、2到n的对象总和大于幸存区的50%,那么大于等于对象年龄为n的对象都会进入老年代,动态年龄判断机制
三:大对象,超过幸存区50%的对象直接进入老年代
老年代空间分配担保机制
年轻代每次minor gc时,会先判断老年代的可用内存大小是否大于年轻代所有存活对象大小,如果没有设置一个参数HandlePromotionFailure,且小于年轻代所有存活对象大小,则会触发fullgc,会回收老年代以及年轻代的垃圾对象,如果设置了该参数,1.8默认开启,则会判断老年代可用空间是否大于历史每一次minor gc时年轻代进入老年代的平均大小,如果小于,则会触发fullgc,fullgc结束后老年代仍然存放不了要进入老年代的对象,则会触发oom,另外如果minor gc后,老年代剩余可用空间小于年轻代将要挪动到老年代的对象大小,则也会触发oom
什么对象会直接进入老年代?
G1以前的大对象(超过幸存区50%)会直接进入老年代,G1时,大对象会直接进入Humongous区域
GC Roots指的是什么?
可达性分析算法,从根节点遍历整个对象图的引用过程
静态变量
线程栈的本地变量
本地方法栈的变量
三色标记算法讲一下?以及如何解决错标问题
三色
黑色
对象树中的节点对象已经标记完成,该对象的成员变量fields都标记完成
灰色
对象树中的节点对象已经标记完成,该对象的成员变量fields没来及标记
白色
对象树中的节点对象没有标记,没有遍历到
错标问题解决
写屏障+增量更新(CMS)
记录引用白色对象插入时的操作
写屏障+原始快照(G1)
记录引用白色对象删除时的操作
https://www.processon.com/view/link/60ed71e6e401fd06dcab523e
使用过的调优工具有哪些?会使用阿里的Arthas吗
jvisualvm
调优经验讲一下,出现了什么问题,如何解决的?
mysql
索引是什么?
帮助mysql高效获取数据的排好序的数据结构
常见的数据结构有哪些?各自的优缺点
二叉树
红黑树
hash
B树
B+树
B树和B+树的区别
B+树非叶子节点不存放数据,只存放索引
B+树叶子节点包含所有的索引
B+树叶子节点之间用指针连接
B+树查询效率更高
常见的索引优化有哪些?为什么
一:尽量不要使用select *,可能会不走索引,尽量加上查询字段,可能会走覆盖索引
二:对于联合索引字段查询时,遵循索引最左列原则
三:尽量将索引的优化级别优化到range以上,最好达到ref,查询效率依次为system>const>eq_ref>ref>range>index>All
四:不要在索引列上加一个数值运算、函数、类型转换等操作,这样会将之前构建的B+树中因为索引改变,导致索引失效
五:尽量少用in和or这种范围查询数据量比较大的场景,尽量减少查询范围
六:使用like时,通配符%在最前面会导致索引失效,通配符在后面可能会走索引
like'%字符串%,这种情况最好使用覆盖索引
like'%字符串%,这种情况最好使用覆盖索引
七:使用!=、<>、not in 、not exists会导致索引失效,全表扫描,因为mysql内部优化器会计算sql执行的成本,如果按照这种方式查询可能比全表扫描时间更长,还不如最终走全表扫描
八:查询条件中范围查询后面的查询条件列会不走索引
九:is null,is not null也不会走索引
十:字符串不加单引号会索引失效
执行计划的每个列的含义?
事务的特性有哪些
原子性
同一个方法中的操作,要么都成功,要么只要有一条失败,都失败,体现在操作上
一致性
体现在数据上是否前后一致,方法都执行完了,结果数据还没处理完
隔离性
事务和事务之间不相互干扰
持久性
事务结束后,磁盘上的数据不会变化
脏写、脏读、不可重复读、幻读分别是什么
这些问题是并发事务处理时的问题
脏写(lost-update)
最后的更新覆盖了其他事务所做的更新操作
脏读
一个事务读取到了另一个事务已经修改好但没有提交的数据,然后继续对这个数据操作,结果之前的事务回滚了,导致这条数据时无效的
不可重复读
同一个查询操作在不同的时刻查到了不同的结果
幻读
一个事务查询到了另一个事务提交的新增的数据
事务的隔离级别讲一下
读未提交
读已提交
可重复读
解决幻读问题
间隙锁
MVVC机制
Innodb默认的隔离级别
可串行化
锁的分类
读锁
针对同一份数据,多个读操作可以同时进行而不会互相影响
写锁
当前写操作没有完成前,它会阻断其他写锁和读锁
行锁
每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。
表锁
每次操作锁住整张表。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;一般用在整表数据迁移的场景。
MVCC机制是什么?
读可提交以及可重复读隔离级别都实现了MVVC机制
简称多版本并发控制机制
通过read-view机制与undo版本链比对机制,使得不同的事务会根据数据版本链对比规则读取同一条数据在版本链上的不同版本数据。
mysql一条语句是如何执行的底层流程是什么
spring
底层原理是什么?
反射+工厂模式实现对象的创建和管理
一:定义bean信息
xml
注解
零配置
二:创建spring容器
三:BeanDefinitionReader接口实现类读取bean的定义信息到容器中,BeanDefinitionMap保存起来
四:BeanFactoryPostProcesser接口实现类对bean的定义信息进行扩展
五:BeanFactory通过反射机制对bean进行实例化
bean的属性值都是默认值
六:填充属性
七:beanPostProcesserBeforeInitailization
初始化之前的操作
八:初始化init方法
九:beanPostProcesserAfterInitailization
初始化之后的操作
实现AOP
十:使用bean对象
十一:销毁
spring最大的特点是什么?
扩展性
解耦合
用容器代替传统创建对象的方式
spring如何整合mybaties?
springMvc的运行流程以及原理是什么?
运行流程
一:客户端发送请求
二:dispatcherServet前端控制器处理请求
web.xml里面有什么东西?
一:servlet定义信息
二:servlet-mapping
三:让容器启动即加载的初始化spring配置文件监听器
spring配置文件里面有什么?
一:包扫描,扫描指定包路径下的对象为bean对象
包扫描什么东西呢?
实体类如何扫描到的?
控制器和映射器在spring容器中如何定义?
二:mvc驱动
这个驱动代表着什么含义?
三:视图解析器
如何书写?
三:调用HandleMapping接口返回处理器映射器链和拦截器
四:调用controller,返回ModelAndView
五:生成view对象
六:视图渲染
七:返回给客户端
底层实现原理
一:
二:
三:
四:
五:
spring的循环依赖如何解决
回答:使用三级缓存解决循环依赖
三级缓存是如何解决循环依赖的?
回答:将bean的实例化和初始化分开解决的
能不能说的再细一点,按照你的理解讲下三级缓存解决循环依赖的过程
一:两个类,每个类中的成员变量属性都是对方的对象的引用,比如A类中的属性为B的引用,B类中属性为A的引用
二:A对象通过反射实例化之后,以lambda表达式形式存放在三级缓存中,接着进行初始化属性B
三:B对象实例化后,会填充属性,使用的属性则是从三级缓存中把半成品的A对象取出来进行初始化
四:B对象初始化完成后,再对A进行初始化
可以用二级缓存代替三级缓存吗?
IOC讲一下
bean的生命周期
AOP原理讲一下
面向切面编程
涉及到的概念有哪些?
切面
切点
连接点
通知
前置通知
在方法之前执行增强方法
后置通知
在方法之后执行增强方法
最终通知
在方法返回前通知
环绕通知
在方法前后执行
异常通知
抛出异常时执行
如何实现AOP?
一:定义一个切面类
二:定义切点
三:定义连接点表达式
拦截器讲一下
动态代理机制讲一下
jdk动态代理
cglib动态代理
零配置是什么?
mybaties
动态代理是什么?
如何防止sql注入?
mybaties的底层原理是什么?
spring如何和mybaties整合?
常见面试题
讲一下hashmap的原理?jdk1.7和jdk1.8的区别
ConcurrentHashMap的底层原理是什么?
如何解决哈希冲突的?
分库分表
项目经验
微服务
springboot
底层原理是什么?
springcloud
0 条评论
下一页