1. JVM
文章仅为自身笔记
1.1 什么是JVM
jvm是Java虚拟机
1.2 Java文件的编译过程
- 程序员编写代码形成.java文件
- 经过javac编译成.class文件
- 再通过JVM的类加载器进入运行时数据区
1.3 什么是运行时数据区
就是我们java运行时的东西的存放区域
其中分为五个模块
线程共享的:
- 方法区
- 堆
线程私有的: - 程序计数器
- 本地方法栈
- java虚拟机栈
- java虚拟机是线程私有的,它的生命周期和线程相同
- 每个方法在执行的同时会创建一个栈帧用于存储局部变量、操作数栈、动态链接、方法出口灯信息
1.4 JVM的垃圾回收机制
垃圾回收机制简称GC
GC主要管理的是Java的堆,Java中的堆是JVM管理的最大的一块内存空间,主要用于存放各种类的实例对象
1.4.1 垃圾回收机制是什么
当程序运行时会产生大量的内存垃圾,为了保证程序运行时的性能,JVM在程序运行时不断的自动进行垃圾回收(GC)
GC是不定时的去清理堆内存中不可达对象(也就是不再引用的对象)。垃圾回收器在java中的执行是自动的,不能强制执行,即使程序员通过 System.gc() 进行手动回收垃圾,也只是建议执行,是否执行是不可知的
手动执行GC
java
System.gc();
1.4.2 Minor GC 、Major GC 、Full GC区别以及触发条件
- Minor GC 是新生代GC。GC频繁,回收速度也比较快
- Major GC 是老年代GC。通常之星Major GC 会连着Minor GC一起执行。Major GC的速度要比Minor GC的速度慢的多
- Full GC 是清理整个堆空间,包括年轻代和老年代
Minor GC 触发条件一般为:
- Eden区满时触发Minor GC,即申请一个对象,发现Eden区不够用时,触发一次Minor GC
- 新建对象大小 > Eden区所剩空间
Major GC 和 Full GC 触发条件一般为: - 每次晋升到老年代的平均大小 > 老年代剩余空间
- Minor GC后存活的对象超过了老年代空间
- 永久代空间不足
- 执行 System.gc()
- CMS GC异常
- 堆内存分配很大的对象
1.5 垃圾回收机制策略
- 引用计数法
- 标记-清除算法
- 标记-整理算法
- 复制算法
- 分代算法
2. Redis
2.1 Redis 数据类型
Redis是键值对(key-value)存储,所以它的数据类型指的value的数据类型
主要包括常见的5种数据类型,分别是:String 、Hash 、List 、Set 、Zset
2.2 应用场景
- 缓存
- 我们可以通过Redis将数据缓存,提高数据响应速度,减少数据库压力
- 计数器
- 日常生活中,我们使用的软件,如抖音的点赞、收藏可以使用Redis完成
- 排行榜
- 我们可以使用 sorted set 和一个计算热度的算法打造一个热度排行榜,例如微博的热点
2.3 常见问题
2.3.1 雪崩、穿透、击穿
雪崩
出现雪崩的情况有两种
- Redis宕机
解决方法: 搭建集群。因为Redis有可能挂掉,所以多增加几台Redis实例(一主多从或者多主多从),这样一台挂掉后还有其他的可以继续工作
- 在某个时间段,Redis中大量的key集体过期
解决方法: 将缓存失效的时间分开。比如我们可以在原有的过期时间的基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效
从而使大量请求直接访问数据库,导致数据库崩掉
穿透
用户访问一条不存在的数据,数据在缓存中没有找到,便访问数据库。如果用户一直请求或者大量访问不存在的数据,变回给数据库造成很大的压力从而导致数据库崩掉。这便是穿透
解决方法:
- 在缓存中缓存空对象。当请求访问一条不存在的数据时,数据库返回一个空对象,并将这个空对象和请求相关联,当下次还是该请求,这时缓存命中,直接返回这个空对象
- 添加布隆过滤器。将所有可能存在的数据缓存放到布隆过滤器中,当有人访问不存在的缓存时迅速返回避免缓存和数据库挂掉
击穿
出现击穿的情况有两种
- 一个冷门key突然被大量用户访问
- 一个热门key,在缓存中时间恰好过期,这时有大量用户进行访问
从而导致数据库压力增大而挂掉
解决方法: 常用的方法是加锁。当key过期时,给缓存和数据库加上一把锁,只允许第一个请求查询数据库,然后把数据库查到的值存储到缓存中,剩下的请求就可以从缓存中直接获取
2.3.2 多线程的情况下,如何保证缓存和数据库的数据一致
在这个问题下,我们首先会考虑两点是先改数据库还是先改缓存。
- 先改数据库再更新缓存
- 会将脏读数据刷新到缓存
- 先改缓存再改数据库
- 缓存更新后,数据库更新失败,则会造成数据不一致,而且用于并发问题
所以在此问题上,我们提出了延迟双删
什么是延迟双删
为了保证数据的一致性,我们可以先删除缓存,再更新数据库,并在间隔一段时间后,再次删除缓存,再把数据库数据插入缓存中
- 缓存更新后,数据库更新失败,则会造成数据不一致,而且用于并发问题
为什么间隔一段时间: 间隔时间是为了让数据库保持主从一致。
3. 反射
3.1 什么是反射
反射就是在运行状态中,对于任意一个类,我们都可以知道这个类的所有属性和方法;对于任意一个对象,我们都能调用它的属性和方法
举个例子就是,黑客可以通过你的姓名来获取你的其他个人信息
3.2 使用场景
目前我们使用反射最多的地方是在框架
像Spring/Spring Boot 、MyBatis等等框架中都大量使用了反射机制
比如我们可以通过@Value这一注解获取配置文件中的值
通过@Autowired获取到一个Service实现类里面的方法和属性
这都是基于反射机制所实现的