关于ThreadLocal问题
ThreadLocal在使用结束的时候,要强制调用remove方法来进行把对应线程持有的ThreadLocalMap的引用给释放掉,否则会引起OOM。
- tomcat为共享线程池,然后ThreadLocal没有主动调用remove方法导致内存泄露
- 没有主动调用remove方法,由于tomcat是线程池复用,所以造成同一个线程中的用户信息不一致。比如一个线程的上下文信息,刚开始是A用户信息,结果一会变成了B用户的信息(线程池内线程复用造成的)
- 线程池中使用ThreadLocal,而使用完ThreadLocal的时候没有对数据进行remove.
JVM调优问题
JVM调优分为两个方面:减少GC回收的频率。发现OOM的情况,然后解决OOM。
优化GC的回收频率,通过修改老年代和新生代的比例,从而让大对象不进入到老年代,这样加快了回收的效率,否则进入到老年代,会频繁的发生Full GC从而造成回收效率低,因为这些大对象就是被废弃的。
而且jvm有个动态调整 suvivor的单数,要强制给关闭掉。否则也会导致调整完老年代和年轻代之后还会发生大对象计入到JVM中。比如都知道Eden和survivor的比例是8:1:1但是实际情况,并不是,就是因为动态调整年轻的的参数未关闭。
有几种情况年轻代的对象会直接进入到老年代
1、survivor区域放不下了,这个时候会直接进入老年代。因为老年代有内存分担的指责。
2、当有大对象的时候,默认是1M,这个时候年轻代对象会直接进入到老年代。
3、年轻带回收的次数达到某个指标的时候,默认是15次则会进入到老年代。
metaspace内存溢出
1
https://www.cnblogs.com/maoyx/p/13934732.html
可达性分析
1
https://www.cnblogs.com/lidong422339/p/17498611.html
案例
1、某个对象中的list对象竟然使用的static修饰,从而导致这个对象一直不能被回收,从而导致OOM。比如:
public static List<String> list=new ArrayList();
2、EXCEL导出的时候一次性的对象太多,从而造成频繁的Full GC,甚至发生OOM。
3、调用HTTP链接的时候,没有设置超时时间从而导致链接一直未关闭,从而导致链接一直未销毁从而造成对象一直在积累从而产生OOM
4、Survivor分配的内存太小,从而造成频繁的发生Full GC。案例如下:
1
https://blog.csdn.net/weixin_43519121/article/details/119835998
5、GC的频繁回收导致cpu飙升
1
https://xie.infoq.cn/article/b6ab2f6faadd2c5a51b0b7037
MYSQL相关
1、有没有没有使用truncat命令,从而导致数据库的表的索引急剧增大,从而导致查询效率非常慢。其实delete语句并没有把数据给删除掉,只是给数据设置了一个标签来证明删除过。 2、spring注解的使用没有理解到位从而造成事务的失效。
3、错误的使用spring的事务注解导致业务异常。比如在递归方法上使用事务注解。 4、订单号取消唯一索引,改成普通索引提高访问的效率;由于分发订单号的系统能够保证唯一性,所以所以可以改用普通索引。而且这个订单号不能使用uuid来做,因为利用不到各种优势。 5、有些数据建立唯一索引的害处其实比普通索引更大;如果这个键真的是唯一索引的话,那么在查询的时候性能差异其实并不是很大
6、mysql explain相关的解释
1
https://www.cnblogs.com/xuanzhi201111/p/4175635.html
mvcc讲解
1
https://www.cnblogs.com/qdhxhz/p/15750866.html
精准学
-
spring的三级缓存各种存的是什么?如何解决循环依赖的
https://www.cnblogs.com/xw-01/p/17561035.html
https://juejin.cn/post/7099745254743474212
解决方案
- 重新设计,避免循环依赖,从根源上解决循环依赖问题
- 使用@Lazy注解,延迟加载
- 使用@DependsOn注解,指定加载的先后关系
- 修改文件名称,改变循环依赖类的加载顺序(Spring是按照文件完整路径递归查找的,按路径+文件名排序,排在前面的先加载)
-
mysql的mvcc
https://www.cnblogs.com/yidengjiagou/p/16663224.html
-
redis常见的5种数据结构,并且内部是如何实现的
https://blog.csdn.net/weixin_41519463/article/details/109208476
-
门面模式和装饰器模式等区别
-
3G JVM 4G docker分配的内存 64G的机器 OOM 分析原因
国创能投
-
nginx是如何平滑启动的
-
mysql是如何保证数据不丢失的
https://juejin.cn/post/7019969643657822216
-
redis链接数飙升,但是请求的qps又不是很多
redis
- redis为什么快?
- Redisson 如何让一个锁等待另一个锁
- lua脚本一定能保证原则性吗?
分布式锁常见的问题
1
https://juejin.cn/post/7011503283768393736
4、redisson的实现原理
1
https://cloud.tencent.com/developer/article/2361352
5、redisson的实现原理
1
2
3
https://blog.csdn.net/weixin_45630885/article/details/125088885
源码解读
https://www.cnblogs.com/jelly12345/p/14699492.html
Redis如何防止内存击穿
通常情况下发生内存击穿的逻辑都是先去查redis缓存,如果redis缓存查不到那么就去mysql查,这个时候如果一个数据查询不到,那么就会频繁的去mysql中查询;既然是这样那么解决方案就有了。
- 直接放弃这种先查内存再查mysql的方案,让api请求直接查redis,查到就返回查不到就返回null
- 插入的时候同步插入到redis
- 更新的时候同步更新redis内部的值
- 如果数据时效性要求不是很高的话还可以使用定时任务,使用定时任务来同步redis缓存
以上的方式没有设置redis的过期时间,缺点就是会造成内存占用多。
ThreadLocal的详解
1
https://www.cnblogs.com/hochan100/p/14977102.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ThreadPoolDemo {
private static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 5, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; ++i) {
poolExecutor.execute(new Runnable() {
@Override
public void run() {
ThreadLocal<BigObject> threadLocal = new ThreadLocal<>();
threadLocal.set(new BigObject());
// 其他业务代码
}
});
Thread.sleep(1000);
}
}
static class BigObject {
// 100M
private byte[] bytes = new byte[100 * 1024 * 1024];
}
}
面试题总结地方
1
https://www.mianshi.online/1454.html
Full GC 和 Minor GC的触发条件
1
https://www.cnblogs.com/fuyuanming/p/16177310.html
静态代理和动态代理
1
https://juejin.cn/post/6844903978342301709
JDK 动态代理和CGLIB动态代理
1
https://www.cnblogs.com/CarpenterLee/p/8241042.html
factorybean的解释 https://juejin.cn/post/6844903759001157640
一些问题总结
1
https://tuonioooo-notebook.gitbook.io/performance-optimization/sqlyou-hua-pian/mysqlyou-hua-pian
多线程
公平锁和非公平锁
https://www.cnblogs.com/vipstone/p/16248006.html
JAVA
锁可重入
1
https://www.cnblogs.com/lidong422339/p/17498611.html
- mybatis在一个对象中拼接集合
- thread如何给分配到另一个线程
ClickHouse的询问
clickhouse在项目中使用作为保存历史订单的数据库,使用的目的是为了方便提高查询效率,因为这个在高峰期查询效率是非常低的。大约有4000w的数据和大约100多个字段,从而造成mysql查询效率很慢。所以采用clickhouse来加快查询速度。
并且还会使用聚合引擎Aggregating来自动实现聚合。
为何要使用clickhouse来做:
- 数据量比较大,大约一张表4000w的数据,并且数据还在以每年800w的速度增长
- 列的数量比较多,这个是一个宽表,用来生产历史报表和导出数据使用的,大约有260个字段左右。
ElasticSearch基础常识
- mapping主要是用来定义文档字段的类型的
- setting主要是来定义索引个数,副本个数等
- term查询不会对进行查询的数据进行分词,标准的分词器会把输入的文档英文按照小写进行分词,如果想检验对某个分词的效果,可以使用分词器来进行分词从而查看结果。 如果想要使用完全匹配,可以使用keyword来进行查询。
- match的查询会把输入的字段查分成term来进行查询,然后计算完结果以后再进行汇总。