常见问题总结

常见问题总结

Posted by bulingfeng on August 2, 2024

关于ThreadLocal问题

ThreadLocal在使用结束的时候,要强制调用remove方法来进行把对应线程持有的ThreadLocalMap的引用给释放掉,否则会引起OOM。

  1. tomcat为共享线程池,然后ThreadLocal没有主动调用remove方法导致内存泄露
  2. 没有主动调用remove方法,由于tomcat是线程池复用,所以造成同一个线程中的用户信息不一致。比如一个线程的上下文信息,刚开始是A用户信息,结果一会变成了B用户的信息(线程池内线程复用造成的)
  3. 线程池中使用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

精准学

  1. spring的三级缓存各种存的是什么?如何解决循环依赖的

    https://www.cnblogs.com/xw-01/p/17561035.html

    https://juejin.cn/post/7099745254743474212

    解决方案

    • 重新设计,避免循环依赖,从根源上解决循环依赖问题
    • 使用@Lazy注解,延迟加载
    • 使用@DependsOn注解,指定加载的先后关系
    • 修改文件名称,改变循环依赖类的加载顺序(Spring是按照文件完整路径递归查找的,按路径+文件名排序,排在前面的先加载)
  2. mysql的mvcc

    https://www.cnblogs.com/yidengjiagou/p/16663224.html

  3. redis常见的5种数据结构,并且内部是如何实现的

    https://blog.csdn.net/weixin_41519463/article/details/109208476

  4. 门面模式和装饰器模式等区别

  5. 3G JVM 4G docker分配的内存 64G的机器 OOM 分析原因

国创能投

  1. nginx是如何平滑启动的

  2. mysql是如何保证数据不丢失的

    https://juejin.cn/post/7019969643657822216

  3. redis链接数飙升,但是请求的qps又不是很多

redis

  1. redis为什么快?
  2. Redisson 如何让一个锁等待另一个锁
  3. 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中查询;既然是这样那么解决方案就有了。

  1. 直接放弃这种先查内存再查mysql的方案,让api请求直接查redis,查到就返回查不到就返回null
  2. 插入的时候同步插入到redis
  3. 更新的时候同步更新redis内部的值
  4. 如果数据时效性要求不是很高的话还可以使用定时任务,使用定时任务来同步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
  1. mybatis在一个对象中拼接集合
  2. thread如何给分配到另一个线程

ClickHouse的询问

clickhouse在项目中使用作为保存历史订单的数据库,使用的目的是为了方便提高查询效率,因为这个在高峰期查询效率是非常低的。大约有4000w的数据和大约100多个字段,从而造成mysql查询效率很慢。所以采用clickhouse来加快查询速度。

并且还会使用聚合引擎Aggregating来自动实现聚合。

为何要使用clickhouse来做:

  1. 数据量比较大,大约一张表4000w的数据,并且数据还在以每年800w的速度增长
  2. 列的数量比较多,这个是一个宽表,用来生产历史报表和导出数据使用的,大约有260个字段左右。

ElasticSearch基础常识

  1. mapping主要是用来定义文档字段的类型的
  2. setting主要是来定义索引个数,副本个数等
  3. term查询不会对进行查询的数据进行分词,标准的分词器会把输入的文档英文按照小写进行分词,如果想检验对某个分词的效果,可以使用分词器来进行分词从而查看结果。 如果想要使用完全匹配,可以使用keyword来进行查询。
  4. match的查询会把输入的字段查分成term来进行查询,然后计算完结果以后再进行汇总。