k8s相关
k8s组件:
kube-apiserver:操作k8s资源的接口,比如:service,deployment,configmap,pv,pvc
kube-scheduler: 根据调度策略,调度pod到对应的节点
kube-proxy: 服务发现(service对应pods实例),负载均衡,健康检查
etcd: 存储k8s元信息,比如:节点信息,pods
kebelet: 创建,删除pods;健康检查;
k8s管理工具:15款备受推崇的K8S可视化工具,你都玩过哪些?-腾讯云开发者社区-腾讯云
Dashboard,KubeSphere,Rancher,Lens,Octant,K9s,Shipyard,Kontena Lens,Kubernetic,Loodse Kubermatic,Portainer,Kubevious,Kuboard,Grafana,Weave Scope
kettle ETL工具
1,数据抽取,数据转换,数据加载
2,核心组件
转换Transformation:负责数据的输入,转换,输出;转换有多个步骤组成。
作业job: 一个作业包含多个转换,执行转换,或者脚本,邮寄通知等操作。
3,可视画操作界面,自定义步骤,插件等。
mongo 集群
副本集:replica set
1,一主多从
2,高可用:主从切换
分片集群 :Sharded Cluster
1,将数据分布到多个分片上
2,每个分片都是一个副本集
mongodb
1, 文档型数据库,,BSON格式存储,类似json格式
2,集合:存储文档,类似数据库表的概念
3,文档:数据基本单位,类似json格式
4,查询语法
db.users.find({ age: 30, name: "Alice" }),user是集合的名称
5,索引,使用b+树,非叶子节点存储索引关键字key,叶子节点存储索引关键字和指向稳定的直指。
HDF5
1,存储科学数据:气象,天文数据,机器学习训练数据,模型参数存储。
2,层次结构:数据结构简化为,数据集(dataset)和组(group)
3,高效存储和访问
分块存储:大型数据集切割成小块存储
压缩存储:支持多种压缩算法GZIP、LZ4
支持索引:快速定位所需数据
并行IO: 支持多个线程同时对文件读写操作
mysql 集群:
异步复制:不用关心从服务器接受数据情况,下个事务执行不受影响。
半同步复制:至少有一个从节点确认已接收到数据,才可进行下个事务执行
全同步复制:所有从节点都要确认接收到数据,可可进行下个事务执行
mysql innodb cluster:
基于mysql group replicaiton;
mysql shell: 创建集群,管理集群节点;
mysql router:提供自动路由功能,应用程序连接到router;
部署模式:支持单主模式,多主模式部署。
mq消息丢失问题:消息生产者到交换器(rabbitTemplate.setConfirmCallback),交换器到队列(rabbitTemplate.setReturnCallback),消费者消费消息(retryTemplate.registerListener可以重写onError方法,重试次数等)
生产者 -> 交换器 -> 队列 <- 消费者
rabbitmq配置项
1,设置连接工厂ConnectionFactory
2,设置消费者数量:消费者线程数量
3,设置消费者接受到消息,消息自动确认
4,设置重试策略,消息消费失败,根据策略重试(重试时间间隔)。
泛型擦除:兼容jdk1.5版本,1.5版本之前是没有泛型概念,在运行期是没有泛型,泛型存在于编译期间。
上界:class Box<T extends Number> ,T 被限制为number子类
下界: List<? super Integer> ,?被限制为integer父类
List<? super Integer> list = new ArrayList<>();
list.add(10); // 正确,因为Integer是Integer的超类型
list.add(10.5); // 编译错误,因为Double不是Integer的超类型
Integer num = list.get(0); // 编译错误,因为无法确定具体类型,只能保证是Number或Object
Number num2 = list.get(0); // 正确,因为Number是Integer的超类型
Object obj = list.get(0); // 正确,因为Object是所有类的超类型
软件开发过程
1,需求阶段
需求文档和原形文档
2,设计阶段(技术方案)
业务分析: 业务背景,现状,痛点,业务目标
业务建模: 业务用例:用户和系统用例 -> 概念模型
概要设计: 系统和用户如何交互,涉及到的系统模块
详细设计: 接口设计,有哪些接口,接口在哪些服务中实现,类图和数据库模型
非功能性设计:稳定性(高可用,高性能,高伸缩,可扩展,高并发);安全性设计
3,开发阶段
编码规范:编码格式,注释,命名
开发计划:根据任务,开发时间,分配任务
4,测试阶段
测试用例文档,测试报告
5,部署运维阶段
部署文档,维护文档,用户文档
系统架构:
保证系统的稳定性
高可用:故障转移,监控检查,负载均衡
高性能:响应时间(低延迟);吞吐量
高伸缩:动态调整资源和pod数量,比如K8S
高扩展:新增功能(服务);拆分服务
高并发:同一时间段内可以处理的请求数量(QPS每秒处理的请求数量)
序列化和反序列化:序列化和反序列化的底层实现原理是什么?_徐刘根的博客-优快云博客_什么是序列化
字节流和字符流:java 字节流与字符流的区别_afa的专栏-优快云博客_字节流与字符流的区别
枚举类:使用enum定义后在编译后默认继承了java.lang.Enum类,而不是普通的继承Object类。enum实现了Serializable和Comparable两个接口。且采用enum声明后,该类会被编译器加上final声明(同String),故该类是无法继承的。
线程池类型 Java线程池-优快云博客
Executors.newCachedThreadPool 核心线程数 = 0,最大线程数 = maxValue; 等待时间 = 60毫秒
弊端:创建最大线程Integer.MAX_VALUE,资源耗尽;
Executors.newFixedThreadPool 核心线程数 = nThreads,最大线程数 = nThreads; 等待时间 = 0毫秒
Executors.newSingleThreadExecutor 核心线程数 = 1,最大线程数 = 1; 等待时间 = 0毫秒
弊端:LinkedBlockingQueue 任务队列是无界,资源耗尽;
Executors.newScheduleThreadPool 核心线程数 = nThread,最大线程数 = maxValue; 等待时间 = 0毫秒
弊端:DelayedWorkQueue无界的延迟阻塞队列,资源耗尽。
Callable和Runnable区别
Callable+Future模式 Java线程池(Callable+Future模式) - 细雨笑澄风 - 博客园
1,Callable 有返回结果,Runnable没有;
2,Callable 可以抛出受检查异常;Runnable不能;
受检查异常:必须在代码里面捕获异常并处理异常,不能忘外抛。
threadpoolExceutor ThreadPoolExcutor 原理探究 - huansky - 博客园
corePoolSize 核心线程数量;maximumPoolSize 最大的线程数量
keepAliveTime 等待任务时间(allowCoreThreadTimeOut = true 核心线程超时回收)
unit 时间单位
workQueue 任务队列
处理任务流出:corePoolSize -> 任务队列 -> maximumPoolSize -> 拒绝
拒绝策略
AbortPolicy:抛出异常。默认
DiscardPolicy:空方法。不执行
CallerRunsPolicy:直接调用run,不启用新的线程执行。
DiscardOldestPolicy:丢弃队列旧的任务,再执行
discard:丢弃;
线程池状态
running:接收任务 + 处理队列任务
shutdown:不接收任务 + 处理队列任务
stop:不接收任务 + 不处理队列任务
tidying :任务已执行完。所有线程已销毁。
terminated :终止状态
switch表达式
byte,short,int,char,String,枚举类型。
跨域问题
例子:你正在访问http://www.example.com
上的网页,并且该网页中的JavaScript代码试图向http://api.anotherdomain.com
发送请求以获取数据。这两个URL不是同源的,因此默认情况下,浏览器会阻止这个请求,除非目标服务器明确允许它
原因:浏览器对 ajax 请求了不同的域名,端口,协议(包括二级域名),浏览器会拒绝接收数据(虽然数据响应了),这是浏览器的一种安全措施:同源策略,限制访问本站点以外的资源。
解决方案:
1,filter过滤器 response 返回添加 header(响应添加头: Access-Control-Allow-origin : * ;允许访问所有的域名;*可以是任何域名;)
2,nginx 网关添加响应头信息
3,@CrossOrigin:用在controller 或方法上
spring-mvc 工作原理
DispatcherServlet 前端控制器:请求系列的组件,最后对视图渲染,返回前端;
HandlerMappering 处理器映射器:找到对应的handle(controller),返回 HandlerExecutionChain 执行链;执行链包括:拦截器+controller
HandlerAdapter 处理器适配器:找到controller方法并执行方法 ;
HttpMessageConverter 消息转换器: 将Java对象转化成json对象返回
(MappingJackson2HttpMessageConverter)
过滤器
filter 过滤器:对 请求和响应 做过滤处理。(Servlet层面)
@Aspect 切面编程:访问方法 前后 抛出异常 等做处理(service层面)
handleInterceptor 接口:调用方法前,方法后拦截;抛出异常拦截(controller层面)
RPC 调用过程 https://blog.youkuaiyun.com/daaikuaichuan/article/details/88595202
服务与服务之间的方法调用,通过TCP网络传输,因为网络传输都是字节流(二进制)数据,所以客户端需要将调用的方法和方法参数序列化,将序列化的数据发送给服务端,服务端再把接受到的数据反序列化,通过哈希表找到对应的调用方法,通过本地方法调用,返回调用结果,服务端将返回结果序列化,通过网络传输,将返回结果传输给客户端,客户端再将方法返回结果反序列化,得到方法的调用结果。
bio ( blocking-io );nio(non-blocking-io);aio(Asynchronous-io);
阻塞IO、非阻塞IO、异步IO的区别_异步io和非阻塞io-优快云博客
阻塞IO:serverSocket.accept()
非阻塞IO:
使用 selector 监听 serverSocketChannel 通道事件,监听到连接事件:serverSocketChannel.accept();不会阻塞
异步IO:
serverChannel.accept(null, new CompletionHandler<...>)
CompletionHandler.completed()有自定义线程池执行
多路复用IO
一个连接,可以多次处理请求和响应;请求和响应可以是无序的。
hashcode :计算在hash表中的索引位置,返回 int 型的 hash 值(不同对象返回值可能相同);效率高;不可靠,用于快速比较集合多个元素;
1, 对象的内存地址转换int值。
2,equals 值相等的对象,他们的hashCode也必须相等
3, hashcode值相等,但是equals值不一定相等;
equals: 比较两个对象的内存地址,类似 == ;比较的较全面,效率低,可靠;
1,equals比较的是两个对象的内容是否相同;
2,object.equals实现的是 == ,比较的是对象引用,也是内存地址;
重载:同一个类中,方法相同,输入输出参数不同
重写:子类继承父类,重写父类的方法;(实现抽象类)
接口和抽象类
interface:多实现implements;不能直接实new;相对抽象类更加抽象;
abstract: 不能直接 new,单继承extends;抽象类有构造函数;有常量,成员属性,静态方法,可以有自己的实现方法 ,可以通过子类继续实例化;对类抽象;
设计模式
策略模式:方法或者算法在运行时确定;减少 if-else 。COLA 扩展点
单例模式:上下文只有一个实例;饿汉模式,懒汉模式。spring bean都是单例。
代理模式:动态,静态;aop切面编程底层逻辑就是动态代理;aop场景(事务,日志,安全)。
工厂模式:隐藏对外创建逻辑。(BeanFactory,ThreadFactory)
BeanFactory:就是IOC容器,所有的Bean都是有它来管理的;另ApplicationContext继承BeanFactory。
BASE理论
https://zhuanlan.zhihu.com/p/147817106
Basically Available(基本可用的):是指在分布式集群节点中,若某个节点宕机,或者数据在节点间复制的过程中,只有部分数据不可用,但不影响整个系统整体的可用性。【节点】
Soft state(软状态):这个状态只是一个中间状态,允许数据在节点集群间操作过程中存在存在一个时延,这个中间状态最终会转化为最终状态【数据】。
Eventual consistency(最终一致性):指数据在分布式集群节点间操作过程中存在时延,与ACID相反,最终一致性不是强一致性,在经过一定时间后,分布式集群节点间的数据拷贝能达到最终一致的状态。【数据】
允许数据最终一致性
CAP理论:CAP理论的理解 - John_nok - 博客园
分区容错性 Partition tolerance:指的分布式系统中的某个节点或者网络分区出现了故障的时候,整个系统仍然能对外提供满足一致性和可用性的服务。也就是说部分故障不影响整体使用。 【网络分区】
可用性Availability: 一直可以正常的做读写操作。简单而言就是客户端一直可以正常访问并得到系统的正常响应。用户角度来看就是不会出现系统操作失败或者访问超时等问题。 (讲的就是任何情况下都可以读,不管有没有写完)【节点】【主从节点切换不能保证可用性】
一致性Consistency:在分布式系统完成某写操作后任何读操作,都应该获取到该写操作写入的那个最新的值。相当于要求分布式系统中的各节点时时刻刻保持数据的一致性。(讲的就是写,要等所有节点写完才可以读)【数据】
可用性允许数据非强一致性的,但是一致性要求数据强一致性。
https://mp.weixin.qq.com/s/oH5ytdIcDZXwugNYPXXsUw
zookerper 和 eureka区别
zookerper:https://www.cnblogs.com/zz-ksw/p/12786067.html
一致性和分区容错性(CP模式)
zookerper集群节点是Leader-Follower领导者-跟随者,
原子广播协议(Zookeeper Atomic Broadcast, ZAB协议)保证强一致性,当超过半数的 Follower 确认接收到该写请求后,Leader 提交更新
主从切换的时候可能导致服务不可用。
eureka:
可用性和分区容错性(AP模式);
eureka集群节点是平等关系;
不能保证数据的一致性。
Maven依赖范围:
maven:
repositories 配置为远程仓库,
localRepository 为本地仓库。
mirror 为远程仓库的代理
spring boot
提供自动配置,减少手动配置,比如
spring-boot-autoconfigure:@springBootApplication 会加载 spring.factories 文件,该文件里有大量的默认配置:jdbc,redis,数据源,监听器,aop ,缓存,jpa
eg:
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration.ConditionalOnClass=com.rabbitmq.client.Channel,org.springframework.amqp.rabbit.core.RabbitTemplate
org.springframework.boot.autoconfigure.data.redis.JedisConnectionConfiguration.ConditionalOnClass=org.apache.commons.pool2.impl.GenericObjectPool,redis.clients.jedis.Jedis,org.springframework.data.redis.connection.jedis.JedisConnection
集成了各种start依赖,比如 spring-boot-starter-web
集成内嵌式服务器:tomcat,undertow
Actuator: 健康检查 /health/liveness
外部化配置: 支持从不同来源加载配置属性,比如 文件系统、环境变量、命令行参数
bootstrap和application区别:
扩展名优先级: properties > yml > yaml
配置文件优先级,由高到低
命令行参数: java -jar app.jar --server.port=9090
Java系统属性: java -Dserver.port=8080 -jar your-spring-boot-app.jar
系统环境变量: export DB_URL=jdbc:mysql://production-db-server:3306/mydatabase;使用@value注解获取值
外包配置文件:java -jar app.jar --spring.config.location=/path/to/your/application-dev.properties
spring.config.location 默认查找顺序:先外部后内部
1,当前应用的根目录:jar文件同目录的application.yml
2,当前应用的配置目录:jar文件同级目录config/application.yml
3,类路径根目录:classpath目录,也是resource目录下的application.yml
3,类路径config子目录:classpath目录,也是resource目录下的config/application.yml
内部配置文件:src/main/resources/application.yml
指定配置文件:@PropertySource("classpath:custom.properties")
默认值配置:
spring循环依赖
场景:A依赖B,B又依赖A,相互依赖
一级缓存:存放已经初始化好的实例对象
二级缓存:存放已经被实例还没有属性赋值、初始化的对象;半成品
三级缓存:存储工厂对象,通过它可以获取二级缓存没有初始化好的对象引用
spring三级缓存
提高性能
解决spring循环依赖问题
保证单例
spring bean生命周期
实例化:调用构造方法,@Constructor
属性赋值:依赖注入,@Autowired
设置bean名称:BeanNameAware.setBeanName(String name)
设置bean工厂:BeanFactoryAware.setBeanFactory(BeanFactory beanFactory),该bean后续可使用ApplicationContext容器
预初始化:BeanPostProcessor.postProcessBeforeInitialization(Object bean, String beanName),修改 Bean 属性【该步骤后面执行@PostConstruct】
初始化:InitializingBean.afterPropertiesSet(),业务逻辑初始化
后初始化:BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName),用于代理创建
使用:应用程序使用
销毁:DisposableBean.destroy()
分布式事务的解决方案:
参与者,协调者 https://www.cnblogs.com/qdhxhz/p/11167025.html
2PC(两阶段提交)
准备阶段 prepar:获取锁,执行DML(增删改查)语句。执行完DML语句,数据只是在内存中,还未 commit 到数据库文件中。(事务预处理)
提交执行阶段:commit/rollback 提交事务或回滚事务。
性能问题:在第一阶段的过程中,所有的参与者资源资源都是被锁住的,只有当所有节点准备完毕,事务 协调者 才会通知进行全局提交,参与者 进行本地事务提交后才会释放资源。【参与者和协调者相互等待,等待过程中,处于阻塞状态】在第一阶段(准备阶段),协调者需要等待所有参与者的响应,这会导致所有参与者在等待协调者指令时处于阻塞状态,无法进行其他操作。
单节点故障:由于协调者的重要性,一旦 协调者 发生故障。参与者 会一直阻塞下去。尤其在第二阶段,协调者 发生故障,那么所有的 参与者 还都处于锁定事务资源的状态中,而无法继续完成事务操作。【协调者发生故障】(虽然协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题),陷入阻塞状态,造成数据不一致问题。
3PC(三阶段提交 )https://www.cnblogs.com/qdhxhz/p/11167025.html
阶段一canCommit:询问事务是否可以提交。
阶段二preCommit:执行事务,但不提交事务。
阶段三doCommit:commit/rollback提交事务或回滚事务。
区别:
把准备阶段分成两个阶段;分成第一阶段和第二阶段;
引入超时机制;参与者没有收到协调者消息超时就提交事务,协调者没有收到所有参与者消息就回个所有事务;
数据不一致问题依然存在,在第二阶段和第三阶段出现网络通信问题,协调者请求中断事务(因为通信故障所以要求中断事务),如果超时提交事务,可能导致事务不一致。
TCC 两阶段事务补偿 https://www.cnblogs.com/jajian/p/10014145.html
场景:电商系统,库存服务和订单服务,购买商品需要保证库存扣减和订单创建两个操作都要成功
try:预处理阶段
业务检查:库存是否足够;资源预留:冻结库存,创建待确认的订单
cofirm/cancel:提交/回滚阶段
Confirm阶段:try阶段执行成功,正式扣减库存;订单状态已确认
cancel阶段:try阶段执行失败,释放冻结的库存;订单状态为取消
每一个操作都需要分别定义TCC方法,对一致性、实时性要求较高的业务场景;开源Hmily
本地消息表 基于本地消息表的分布式事务解决方案总结 - 知乎
场景:电商系统,订单服务和库存服务
订单服务:订单支付成功后,在本地消息表中,插入一条订单消息,状态为待消费,并发送mq消息给库存服务;
库存服务:监听消息并成功消费后,再发送mq消息告诉订单服务消费成功,订单服务修改本地消息表的订单消息状态为已消费。
注意:
消费逻辑需幂等操作;
消息丢失:定时捞取待消费的消息,重新消费。
ebay提出,基于base理论。
事务消息 还不知道事务消息吗?这篇文章带你全面扫盲! - 楼下小黑哥 - 博客园
场景:电商系统,订单服务和库存服务
订单服务:创建订单记录,发送半消息(消息不可见),本地事务提交后,发送确认消息(消息可消费)
库存服务:监听队列并消费消息
注意:
若发送确认消息失败:事务反查机制,用来反查本地事务状态
阿里开源RocketMQ
最大努力通知:本地消息表和事务消息。适用外部系统
分布式事务比较:
zookeeper分布式锁 Zookeeper 分布式锁 - 图解 - 秒懂-优快云博客
为获取锁的客户端创建一个临时顺序节点,排队监听前一个节点。
监听到前一个节点删除事件(锁释放),判断是否最小节点,则成功获取锁;
注意:
若获取到锁的客户端失联后,会自动删除临时节点,后面的节点也能监听到删除事件。
curator-client.jar: 对zookeeper的API进行封装的。
Leader创建删除节点,然后同步Follower。【CP模式】
性能不高,建议使用redis,但是可靠
redis分布式锁 https://blog.youkuaiyun.com/shuangyueliao/article/details/89344256
加锁机制:若key不存在,则设置一个hash表的数据结构,可设置客户端的ID,重入锁次数,默认生存时间30秒。
互斥机制:其他客户端发现key已经存在,获取value值,若ID不是自己客户端的ID,返回生存时间,尝试自旋尝试获取锁。
自动延期:加锁成功后,后台启用新的线程,每10S检测客户端持有锁情况,若还在持有锁,会延迟key的生存时间。
释放锁机制:删除当前加锁的key,如果是重入锁,会先减1操作,直到为0。
注意:
Redisson开源框架,底层使用的是lua脚本,保证业务逻辑的原子性
主从切换,可能造成脏数据产生,不能保证数据一致性。
使用案例:service层面
@CacheConfig(cacheNames = "accountKeyword")类上面配置缓存
@Cacheable 查询方法使用,缓存结果
@CacheEvict(allEntries = true) 删除缓存
@CachePut() 更新缓存
redis配置项RedisConfig
1,过期时间设置,默认6小时
2,设置序列化方式FastJsonRedisSerializer,以json格式存储
3,自定义key生成策略
4,配置redisTemplate,指定key序列化为StringRedisSerializer,并设置连接工厂RedisConnectionFactory。
5,异常处理:捕获异常并记录日志。
Redis集群
Redis集群详解_变成习惯-优快云博客_redis集群
1,主从模式
读写分离,主数据库处理写请求,从数据库处理读请求;数据变化由主库同步到从库。
一主多从,一个master可以有多个slave。
不支持主从切换,但可继续提供读请求。【不具备高可用性】
初始化:
从库发送sync命令
主库收到命令后,保存快照和命令,发送给从库
从库收到快照文件和写命令初始化数据
数据同步:
主库收到写命令后,发送给从库
2,Sentinel 哨兵模式
哨兵模式建立在主从模式上,可解决主从切换问题【具备高可用】
sentinel进程监控redis运行情况
sentinel可启动多个,形成集群,sentinel相互监督
客户端连接的是 setinel,而不是 redis
工作机制:
sentinel每秒一次,发送ping命令给主从库
主从有效时间内没有回复,标记为主观下线
其他sentinel发送ping命令,确认是否主观下线
指定时间范围内,达到配置的sentinel数量,标记客观下线,开始选举新的主库
3,Cluster集群模式
数据分片:解决单机容量有限问题
每个分片:一主多从,故障转移
缓存 https://blog.youkuaiyun.com/kongtiao5/article/details/82771694
缓存穿透:请求ID为“-1”的数据或不存在的数据;导致数据库压力过大。
解决方案:对ID进行缓存,值为空,有效期30秒。
缓存击穿:缓存没有数据(过期导致),数据库有数据;导致数据库压力大。
解决方案:
1,设置热点数据不过期。
2,使用互斥锁。
缓存雪崩:大量的数据都到过期时间了,查询数据库导致压力大;
解决方案:
1,缓存数据的过期时间设置随机
过期删除策略: 过期数据
定时删除:创建定时器,定时删除。
惰性删除:获取key的时候检测删除。
定期删除:定期对设置过期时间的key检测删除。
redis,默认使用 惰性删除和定期删除
淘汰策略: 内存不足
volatile-lru:从已设置过期时间的数据集中挑选出最近最少使用的数据淘汰。
volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
allkeys-lru:从数据集中挑选最近最少使用的数据淘汰。
allkeys-random:从数据集中选择任意数据淘汰。
no-enviction:不删除。默认值。
redis 持久化机制
rdb内存快照:dump.rdb的二进制文件。启动优先级低,体积小,恢复快。容易丢失数据
aof:操作命令记录进appendonly.aof文件。启动优先级高,体积大,恢复慢。
rdb过期key不入库,aof过期数据可能入库。
redis数据类型
string 字符串
list: 有序
set: 无序,唯一
sorted set: 有序,唯一
hash: 键值对,适合存储对象
aop切面编程
代理是实现aop核心技术之一
使用场景:安全,事务,日志
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义一个接口
interface MyService {
void doSomething();
}
// 实现该接口的服务类
class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("Executing doSomething...");
}
}
// 自定义的 InvocationHandler
class MyInvocationHandler implements InvocationHandler {
private final Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args); // 调用目标对象的方法
System.out.println("After method: " + method.getName());
return result;
}
}
public class Main {
public static void main(String[] args) {
MyService service = new MyServiceImpl();
// 创建代理实例
MyService proxyInstance = (MyService) Proxy.newProxyInstance(
MyService.class.getClassLoader(), // 类加载器
new Class<?>[]{MyService.class}, // 接口数组
new MyInvocationHandler(service) // 调用处理器
);
// 通过代理调用方法
proxyInstance.doSomething();
}
}
饿汉模式:类静态变量 private static class = new class(),类加载的时候初始化,提供对外访问的静态方法。
懒汉模式:类静态变量 private static class = null;,定义静态方法,如果为空进行初始化,否则直接返回。
区别:
饿汉模式:类加载时初始化
懒汉模式:使用时初始化。
锁的状态
jvm层面优化技术
无锁状态:没有线程持有该锁
偏向锁状态:一个资源只有一个线程访问;eg:访问代码块,实例对象头记录该线程ID;
轻量级锁状态:一个资源有多个线程访问;eg:CAS自旋
重量级锁状态:自旋时间过长或竞争激烈;线程会被阻塞并挂起
锁的升级
偏向锁 -> 轻量锁 -> 重量锁
消息队列
mq作用:解耦异步,流量削峰
TCP三次握手:
第一次:客户端发送连接请求,syn同步序列编号
第二次:服务端响应连接请求,syn+ack
第三次:客户端响应服务端,ack
场景:打电话
a: 喂,能听得到我说话吗?
b: 我能听得到你说话,你能听得到我说话吗?
a: 我也能听得到你说话,那我们开始聊天吧!
构造器
1,静态初始化:加载class文件时调用,执行所有静态变量和静态语句块。修饰符:static
2,构造函数:new操作符,Constructor.newInstance(),Object.clone(),ObjectInputStream.getObject()。
java对象内存布局 https://zhuanlan.zhihu.com/p/50984945
1,对象头
hash码,GC垃圾回收年龄,锁的不同状态,偏向锁存储线程ID,class类型指针
2,实例数据:定义的字段信息
3,对象填充:对象大小必须是,8倍的字节数
加载区别 https://blog.youkuaiyun.com/fn_2015/article/details/79422367
Class.forName():加载且被初始化;执行class中的静态代码块
ClassLoader.laodClass():加载且不会被初始化;不会执行class中的静态代码块
threadLocal:set和get方法,设置线程变量副本。获取当前线程 里面的 ThreadLocalMap,使用threadLocal作为ThreadLocalMap的key,获取entry里面的value值。
内存泄漏 ThreadLocal 内存泄漏 代码演示 实例演示_刘本龙的专栏-优快云博客_threadlocal内存泄漏实例
value 值无法被访问:因为 key = null ,且无法被 gc : 因为 value = 对象; threadLocal 作为 value 的 key ,且是弱引用。
问题在于 threadLocal 实例是否能被回收,被回收的话,就会造成内存泄漏。回收 threadLocal 的条件:没有强引用。
remove() :key = null,value = null ; set() , get() 最后的条件也是如此 key = null,value = null ;
因为threadLocal作为弱引用指向threadLocal实例,弱引用指向的threadLocal实例可被gc回收,导致threadLocal指向为空的内存,但是获取value值需要使用threadLocal,此时threadLocal为空,value值占用内存一直没有被释放,因为value一直在线程里的threadLocalMap里面。内存泄漏:无法使用且无法释放的内存。
核心:threadLocal只是作为线程操作的读写入口和key,使用完后被gc后,写入的值无法被找到和回收。
https://blog.youkuaiyun.com/liubenlong007/article/details/107046897
JVM引用类型 https://www.cnblogs.com/liyutian/p/9690974.html
强引用 Strong Reference: GC 不回收。
软引用 Soft Reference:非必需但仍有用的对象,内存不足的时候回收;被 SoftReference 所关联的对象会被回收(若对象仍被强引用指向,仍不能回收);
弱引用 Weak Reference:无论内存是否足够都会被 GC 回收。
虚引用 Phantom Reference:不能通过该引用获得对象, gc 时返回一个通知。
Java基础
String,StringBuilder,StringBuffer区别
可变性:string不可变,其他的都是可变的。
安全性:string不可变是安全的,stringbuffer方法都加了关键字synchronized,stringbuilder不安全。
创建对象的几种方式:
使用new关键字,反射机制,对象克隆,反序列化。
jdk8新特性
1,lambda表达式:将函数作为参数传递给方法
2,stream api: 比如过滤,排序,聚合,映射。
3,接口可定义默认方法和静态方法
volatile的两点作用 https://www.cnblogs.com/xd502djj/p/9873067.html
1,可见性:当一个线程修改了 volatile
变量的值时,这个变化会立即对所有其他线程可见;
2,禁止指令重排:防止编译器和处理器为了优化性能而对代码进行重排序
finally:
覆盖try和catch里面的return
集合
list:是元素可重复,元素有序;
arraylist 数据结构是数组,查询较快(索引),增删效率低,因为要移动元素
linkedlist 数据结构是双向链表,查询慢,增删效率高
set: 元素不可重复,元素无序
hashset: 底层是hashmap实现,key存储的是元素,每次迭代顺序不一样
HashMap 掘金
数据结构:数组+链表 + 红黑树;
存取原理:检查数组是否为空或长度为0,则进行扩容(复制数组)。put需 算出位置 index=hashCode(key) & (length -1),使用equesl()比较两个key,相同则替换值,不同则插入(1.7头插入:扩容容易造成环形链表,1.8尾插入避免环形链表,但在多线程下是不安全的)。get 算出位置index=hashCode(key) & (length -1),使用equals()比较两个key,相同则返回值,链表迭代比较。
Java7和Java8的区别
1.7 节点是entry;头插入;
1.8 节点是node,尾插入法,引入红黑树,大于 8 会自动转化为红黑树,小于 6 重新变为链表。
HashMap的扩容方式
创建一个新的Entry空数组,长度是原数组的2倍;
ReHash:遍历原Entry数组,把所有的Entry重新Hash到新数组;
阀值:threshold = capacity * load factor,capacity = 16 ,load factor = 0.75
ConcurrentHashMap 并发容器
1.8是数组+链表+红黑树结构,使用Synchronized关键字。
jdk1.7 ConcurrentHashMap是Segment数组和HashEntry数组组成,segment的分段锁机制,继承reentrantLock锁控制并发。
红黑树平衡二叉树,左右高度差不多。特性:节点是黑或者红,根节点和叶子节点是黑色,节点 = 红色,他的子节点 = 黑色
区别:红黑树大致平衡,不是完全平衡,可三次旋转解决平衡问题,平衡二叉树绝对平衡,多次旋转
线程中断 https://www.cnblogs.com/onlywujun/p/3565082.html
void thread.interrupt() :其作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),但实际上只是给线程设置一个中断标志,线程仍会继续运行。
boolean interrupted() :作用是测试当前线程是否被中断(检查中断标志),返回一个boolean并清除中断状态,第二次再调用时中断状态已经被清除,将返回一个false。
boolean isInterrupted():作用是只测试此线程是否被中断 ,不清除中断状态。
Object.wait(), Thread.sleep() ,Thread.join(), Condition.await(),throws InterruptedException
方法,会不断的轮询监听 interrupted 标志位,发现其设置为true后,会停止阻塞并抛出 InterruptedException异常。
lock 和 synchronized 区别 https://www.cnblogs.com/simpleDi/p/11517552.html
synchronized : JVM 层面实现
自动加锁和释放锁
锁定对象:this、class
自动释放锁:执行完代码块;异常时;wait()方法;
中断:等待过程中无法响应中断;
非公平锁;
lock : jdk 层面的锁,
手动加锁和释放锁;
中断:可响应中断;
公平和非公平锁;
wait-notify java并发编程基础之等待通知机制wait/notify原理分析_tom有cat-优快云博客
配合 synchronized(非公平锁,可重入,不可中断)使用。wait线程调用wait方法,wait线程阻塞,进入等待集中。notify线程调用notify,会唤醒wait线程,但是wait线程不会立马执行,因为notify线程还没有释放锁,wait线程如果没有竞争到锁会进入同步队列中继续阻塞,如果竞争到锁,会继续执行wait方法后面的代码。等待notify线程执行结束后释放锁,wait线程获取锁后再执行。
ReentrantLock ReentrantLock原理_路漫漫,水迢迢-优快云博客_reentrantlock
CAS原子操作+AQS同步器来实现。通过CAS尝试获取锁,如果此时已经有线程占据了锁,那就加入AQS队列(先进先出)并且被挂起。当锁被释放之后,唤醒下一个线程,然后CAS再次尝试获取锁。ReentrantLock和synchronized都是可重入锁。state=0表示锁未被占用,反之则被占用。 独占锁
AbstractQueuedSynchronizer.acquire():获取锁 -> 入队 -> 获取锁 -> 挂起
CountDownLatch 计数器 https://www.jianshu.com/p/e233bb37d2e6
1,使一个线程等待其他线程各自执行完毕后再执行;
2,通过一个计数器来实现的,计数器的初始值是线程的数量;每当一个线程执行完毕后,计数器的值就-1,当计数器的值为 0 时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。countDown() 和 await()
shouldParkAfterFailedAcquire():找到前驱状态为 -1 下的节点排队等候;
【车做满人司机才可以发动车子走】
Semaphore 信号量 https://zhuanlan.zhihu.com/p/98593407
信号量,资源使用限制;acquire() -1 和 release() +1 ;共享锁
tryReleaseShared():尝试释放令牌
【停车场例子】
CyclicBarrier 循环栅栏 Java并发编程之CyclicBarrier详解_Stay Hungry, Stay Foolish-优快云博客_cyclicbarrier, 深入理解CyclicBarrier原理_晨初听雨的博客-优快云博客_cyclicbarrier
循环栅栏,可循环利用的屏障。调用 await 方法阻塞(--count 减1),最后一个线程调用 await 方法(count == 0)后唤醒所有的线程,进入下一代;
【旅行团等所有人到齐了才开始出发】
CyclicBarrier:内部基于 Condition 实现,可重复使用;使用 --count 计数。
CountDownLatch:内部使用AQS实现,使用 --state 计数。
区别:AQS是同步队列,Condition里有多个等待队列,Condition 唤醒时将等待队列里头一个节点转移至同步队列尾部且继续阻塞;Condition 阻塞时将当前线程封装一个节点加入等待队列尾部同时释放锁唤醒同步队列的头节点。
Condition https://blog.youkuaiyun.com/a1439775520/article/details/98471610
Condition.await()阻塞且释放锁。condition.signal()唤醒被阻塞的线程。在 lock 里面使用;Condition:等待队列 FIFO
类似object.wait 和 object.notify 需 在 synchronize 里面使用。
CAS:乐观锁compare And swap先比较再替换;存在ABA问题和长时间循环cpu开销大问题;版本号;当前内存存储的值和期望值一样,就更新当前内存的值。
AQS:AbstractQueuedSynchronizer队列同步器。两个队列:同步队列和条件等待队列(可以多个)。同时队列保持着一个状态值。
dubbo协议:
dubbo://,rmi://,hessian://,http://,webservice://,thrift://,memcached://,redis://,rest://,grpc://。
Java原生序列化:需要实现Serializable接口。
http版本
spring-boot 默认支持http/1.1,spring-boot2,也支持http/2,但是需要配置SSL证书
HTTP/1.0 短连接:每次通信完成后,连接就会被释放
HTTP/1.1 长连接(持久连接):
长时间内保持连接状态。
请求1篇博客最多建立多个并行连接,默认6个连接(6个TCP连接)
HTTP/2(h2):
多路复用:同一个连接支持并行请求和响应,eg:请求1篇博客最多建立1个连接(1个TCP连接)
数据压缩:对请求和响应head头部压缩
支持服务器推送:向客户端发送资源
dubbo
启动注册中心后,客户端和服务端向注册中心注册服务和订阅服务,客户端根据负载均衡调用服务;注册中心会推送更新后的服务到客户端。
Eureka:服务治理组件
为什么Eureka Client获取服务实例这么慢 - 炎泽 - 博客园,包含eureka service和eureka client,service是注册中心,client是服务提供者和服务调用者。Eureka原理及工作流程_Alisa的博客-优快云博客_eureka原理及执行流程
Eureka 注册延迟_简简单单Onlinezuozuo-优快云博客_eureka 延迟注册
程序员笔记|详解Eureka 缓存机制 - 宜信技术 - 博客园
一级缓存:服务即时更新,并标记二级缓存数据为无效数据(事件通知实现)
二级缓存:当有请求访问二级缓存时,二级缓存才会从一级缓存中同步数据。
三级缓存:每隔30秒从二级缓存中同步数据。
eureka客户端:服务调用者每隔30秒从三级缓存中缓存数据。
心跳续约:由client 定期调用http接口,service提供接口 (定时心跳);
Hystrix https://www.cnblogs.com/qdhxhz/p/9581440.html
容错管理组件,超时或异常情况;
@EnableCircuitBreaker 开启熔断器
@HystrixCommand(fallbackMethod = "loadFallback") 断路器注解
@FeignClient(name = "USERSERVICE", fallback = UserServiceFallback.class) 断路器注解
服务熔断 -> 服务降级:配置 fallback 回调,返回一个缺省值;
Hystrix配置
circuitBreaker.requestVolumeThreshold //滑动窗口的大小,默认为20
circuitBreaker.sleepWindowInMilliseconds //过多长时间,熔断器再次检测是否开启,默认为5000,即5s钟
circuitBreaker.errorThresholdPercentage //错误率,默认50%
每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。
Ribbon:负载均衡组件,默认轮询算法。(spring-cloud-loadbalancer替代,ribbon进入维护模式)
负载均衡算法:为 随机,轮询,哈希,最小压力,权重。
Feign:声明式服务调用组件,基于Ribbon和Hystrix的,是一款客户端HTTP调用组件
Feign内部集成Ribbon,构建好http请求后交给Ribbon处理
gateway Zuul已被淘汰
微服务网关组件,统一入口,路由转发,鉴权;
内部服务之间的调用,不再经过网关;request -》网关 -》A服务 -》B服务
pre filters :前置过滤器;请求被路由之前执行;请求认证,负载均衡,日志
post filters :后置过滤器;调用远程服务之后执行;统计服务性能,响应做处理等;
routing filters :路由后过滤器;路由之后,调用远程服务之前执行。
error filters :异常过滤器;其他过滤器器发生异常或远程服务调用超时 触发执行;异常处理
服务类型:调度中心,认证中心,注册中心
分布式任务调度 参考XXL-JOB快速入门 - 简书
启动调度中心,执行器(主动或被动)添加到调度中心里,调度中心进行任务调用,任务执行完回调给调度中心。
单点登录 单点登录(SSO)看这一篇就够了-阿里云开发者社区
客户端请求到认证中心获取token,再去请求服务端,服务端拿着token到认证中心验证,通过则放行。客户端首次访问服务端,引导客户端到认证中心登录认证。
mybatis #{}和${}区别
${} 字符串替换,不能防止sql注入。
#{} 预编译参数,先替换成 ?,再根据参数类型绑定值;
mybatis相关
mybatis插件原理 一针见血MyBatis插件机制 - MyBatis中文官网
底层通过拦截器拦截四大对象实现:
ParameterHandler参数处理对象:Java对象映射SQL参数
ResultSetHandler结果处理对象:SQL结果映射到Java对象
StatementHandler数据库处理对象:执行SQL语句
Executor:MyBatis的执行器:提交或回滚事务
mybatis 缓存 https://www.cnblogs.com/wuzhenzhao/p/11103043.html
一级缓存(本地缓存)是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在sqlSession对象中有一个数据结构(BaseExecutor -> PerpetualCache -> HashMap)用于缓存数据;SqlSession 对象之间的数据相互隔离
SqlSession会话只要有更新操作(update,delete,insert),就会清空 PerpetualCache 对象里的数据。
二级缓存
二级缓存是Mapper命名空间级别的缓存,多个SqlSession可以共享同一个二级缓存CachingExecutor;
默认没有开启,可配置redis开启
更新操作会清空缓存(update,delete,insert);使用LRU清除缓存;
查询顺序:一级缓存 ;二级缓存 ;数据库。
hibernate 缓存
一级缓存:session级别缓存
二级缓存:应用级别的缓存
二级缓存配置:可用redis实现
总结:不管是mybatis,hibernate,二级缓存都是自动读写
B树和B+树(二叉树 -> 平衡二叉树 -> m叉树 -> m叉平衡树(B树) -> B+树)
二叉树:产生退化现象(链表)
平衡二叉树:让每层的节点多一些,减少遍历高度
m叉树:有退化现象
m叉平衡树【B树】:节点包括key和value
B+树:节点只存放key,value放在叶子节点上,相邻的叶子节点增加指针
目的:减少遍历高度(减少磁盘访问的次数)
这个时候每个节点既放了key又放了value.怎样使每个节点放尽可能多的key值,以减少遍历高度也就是访问磁盘的次数
可以将每个节点只放key值,将value值放在叶子节点,在叶子节点的value值增加指向相邻节点的指针,这就是优化后的B+树
SQL执行流程 一分钟学会数据库sql查询原理及查询执行sql流程
连接器 -》 分析器 -》 优化器 -》 执行器
一:客户端将sql发送给数据库服务器。(连接器)
二:服务器解析sql语句(分析器)
1,查询缓存,如果在缓存中查询到该执行计划,执行该计划返回查询数据。
2,语法校验(符合解析树规则) -> 语义校验(例:表列是否存在)-> 获取对象锁 (表加锁) -> 校验用户权限。
三,优化sql(优化器)
多个索引使用哪个索引,
确定执行路径,放在缓存里,
关联查询先查哪张表。
四,执行sql(执行器)
explain执行计划 explain执行计划详解_eagle89的专栏-优快云博客_explain执行计划
id : select 标识,从小到大顺序执行
select_type:查询类型
simple : 简单查询
primary :复杂查询,包括子查询,union;id > 2
devived : 起源,衍生查询;from (子查询)
dependent subquery : 依赖查询 in (子查询)
subquery:子查询 = (子查询)
union : 联合查询
table:操作的表名
type 访问类型
null :不访问表或索引
system :只有一行数据
const :通过索引查询
eq_ref :唯一索引扫描
ref :普通索引扫描,非唯一索引扫描
ref_or_null :类似 ref ,可搜索值为 null 的行
index_merge :索引联合优化,比如 where id = 11011 or tenant_id = 8888;
range : 索引范围扫描
index : 索引扫描
all :全部扫描
possible_keys : 可能使用的索引
key :实际使用的索引
key_len:索引长度;多列索引根据这个字段判断是否使用所有的索引列
ref :索引列与条件进行比较的列
rows : 估计需要检查的行数
索引失效 索引失效的7种情况 - liehen2046 - 博客园
未建索引,or,不符合最左匹配原则,like %开头,表达式或函数,类型转换(varchar == number),varchar字段无单引号(phone = 13515651145),not in ,not exist ,is null;
当创建(a,b,c)联合索引时,相当于创建了(a)单列索引,(a,b)联合索引以及(a,b,c)联合索引 ,这是就是最左匹配原则;
数据库调优/SQL调优
https://www.zhihu.com/question/36431635
索引优化:
查询表的字段尽量被覆盖,不用再回表;
避免索引失效,索引字段上注意表达式,函数使用,会使索引失效。explain分析查询计划。
查询优化:
查询需要的字段,尽量不使用 * 查询所有的数据。
尽量减少子查询或者关联查询
模式设计优化:
使用合适的数据类型:char和varchar
字段尽量使用默认值,null占用的空间更大;
varchar和char区别
char:固定长度,不足空格填充,最大255个字符 200多
varchar:可变长度,按实际字符长度存储,最大65532个字符 6万多
单字节字符集(如 Latin1):一个字符占用一个字节
多字节字符集(如 UTF-8):一个字符占用1 - 4个字节
tinyint 占用1个字节 最大值255 200多
smallint 2个字节,最大值65535 6万多
mediumint 3个字节,最大值16777215 1600万
int 4个字节,4294967295 42亿
bigint 8个字节,18446744073709551615 兆级别
@Transactional事务失效情况
1,非public关键字修饰的方法
2,注解所在的类未被Spring管理
3,在同一个类里内部调用
mysql索引
mysql 相关
mysql引擎
事务底层实现
重做日志redo log:记录修改后的数据(insert,updae,delete)
回滚日志undo log:记录修改前的数据;
ACID特性
原子性 (Atomicity):undo log事务回滚
隔离性 (Isolation):隔离级别,锁机制,多版本并发控制
一致性 (Consistency):约束条件和检查:非空约束,外键约束【数据层面】
数据层面约束
业务逻辑层面约束
持久性 (Durability):redo log保证持久性
锁机制
排他锁:
当前事务可以读写,其他事务无法读和写
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;隐含加锁
SELECT * FROM accounts WHERE account_id = 1 FOR UPDATE; 显示加锁
共享锁:
多个事务共同读同一行数据,不允许任何事物写入该行
SELECT stock FROM products WHERE product_id = 1 LOCK IN SHARE MODE;加锁
in 和 exists 比较:
select * from A where id in(select id from B):适用于小到中等规模的数据集;返回所有匹配项
select a.* from A a where exists(select 1 from B b where a.id=b.id):适用于较大的数据集;EXISTS
关键字用于测试是否存在满足条件的记录,它只关心是否有至少一条记录符合要求,而不关心具体的数量。返回boolean值。
内存分页 和 物理分页 https://www.cnblogs.com/cocoxu1992/p/10974325.html
内存分页:先从数据库获取所有的数据,缓存到内存,然后再进行分页;例如:Mybatis 使用 RowBounds 对象进行内存分页
物理分页:使用 sql 语句的 limit 分页参数 在数据库层面执行,返回分页结果;例如:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10;hibernate 物理分页
Mybatis-Paginator ,Mybatis-PageHelper 是 mybaites 物理分页插件
left jion和inner join的区别
left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 。
right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录。
inner join(等值连接) 只返回两个表中联结字段相等的行就。
spring事务传播行为 看完就明白_spring事务的7种传播行为_gnixlee的博客-优快云博客_事务传播行为
事务的隔离级别
脏读:一个事务读到另一个事务未提交的数据
不可重复读:一个事务读到另一个事务已经提交的 update 数据,导致一个事务中多次查询结果不一致
幻读:一个事务读到另一个事务已经提交的 insert 数据,导致一个事务中多次查询结果不一致
mysql:默认的可重复读
oracle : 默认的读已提交
产生死锁条件
1,互斥:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
2,保持与请求:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
3,不可剥夺:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
4,循环等待: 若干进程间形成首尾相接循环等待资源的关系
gc算法
标记-清除(mark-Sweep):标记无用对象,然后进行清除回收。缺点:产生垃圾碎片。
复制(copy):按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象标记复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。
标记-整理(mark-compact):标记无用对象,让所有存活的对象都移向一端,然后直接清除掉端边界以外的内存
对象是否存活
引用计数法:对象里有计数器,该方法已被弃用;不能解决对象相互引用问题;
可达性分析算法 gc root 通过 heap.dump 日志文件获取。
gc root:
1、局部变量表(Local Variables)中的对象引用
2、 本地方法栈中的对象引用
3、常量池中的对象
4、静态变量
类加载的过程. JVM优化及面试热点分析_weixin_51297617的博客-优快云博客_jvm热点
链接{验证,准备,解析}
校验:验证class文件合法性。
准备:分配空间,a = 0【常量直接初始化】。eg:static int a = 10;
解析:符号引用转换直接引用(内存地址)。
初始化:静态代码的执行;初始化a = 10;
jvm虚拟机
死锁排查:
jvisualvm:命令行可视化工具,性能分析和调优;线程dump
jps: 查看Java进程
jstack:查看线程信息,显示锁信息
jvm调优
1,内存模型:堆内存和非堆内存
2,监控jvm性能工具:
jps:查看Java进程
jmap: 生成堆转储文件,用于分析内存泄漏问题
jstack: 生成线程转储文件,用于线程死锁问题
jstat: 监控垃圾回收情况
内存泄漏:
jvm 内存泄漏分析:heap dump(jmap) -> mat(memory anlayzer tool 直方图:根据类的数量和内存使用量排线)
新生代和老年代内存比:1/3,2/3 full gc
新生代分为 eden区(80%),survivor(from 10%,to 10%)
对象在堆中的过程:
新建的对象直接放在eden区,经过minor gc会把存活的对象放入survivor其中一个区域,存活的对象来自eden区和survivor其中一个区域,进入survivor的对象就不能再放入eden区了;反复minor gc 后达到年龄进入到老年代。
对象进入老年代:
gc15次(岁),
大对象(默认未设置,可以设置1M)
minor gc的时候,复制存活对象到survivor其中一块区域放不下的情况
gc类型
方法区:
永久带 1.7--> 元空间1.8(本地内存)
类的元信息:类的名称,方法字段信息
JIT编译后的代码:Java字节码编译成机器码
类的静态变量和常量区别:final
静态变量
常量池
虚拟机栈:Java栈,创建每个线程时都会创建一个虚拟机栈,其内部保存一个个的栈帧(stack Frame) ,对应着一次次的Java方法调用。
栈溢出:StackOverFlowError 方法调用链过长导致;超出虚拟机规定的调用深度,递归调用。
内存溢出:OutOfMemeryError 内存不足。
栈:调用方法创建栈帧,入栈和出栈,参数,局部参数,返回参数,对象引用等保存在栈帧,类似局部变量区表。
类加载器(创建Class对象) https://blog.youkuaiyun.com/m0_38075425/article/details/81627349
Bootstrp ClassLoader:启动类加载器,加载 jre -> lib(jar包,包括:ExtClassLoader,AppClassLoader);c++实现。
Launcher.ExtClassLoader:扩展类加载器,加载 jre -> lib -> ext(jar包)。
Launcher.AppClassLoader:应用类加载器,加载 classpath 路径 jar 包。
关系:AppClassLoader -> ExtClassLoader -> Bootstrp ClassLoader
双亲委托机制:
检查缓存是否已有该类,委托父类加载,一直委托到启动类加载器,父类未加载此类,自己才去加载此类,放入缓存中。
对象地址:System.identityHashCode
string.intern():返回常量池中的字符串的内存地址。