• 作者:老汪软件技巧
  • 发表时间:2024-08-22 11:02
  • 浏览量:

在某客上刷到一条很有意思的帖子:“我在美团实习犯下的七宗罪”,看完忍不住送了一朵小花花。真的是好活啊,文本输出能力太强了。

我只能说,这位牛友绝对是可塑之才,在美团的上升空间贼大,不信我们等着瞧。就这 7 句小总结,透露出一种浓烈的高觉悟,值得每一个在实习的小伙伴去学习(手动狗头)。

换成我,却只能写出下面这种没水平的工作总结,甘拜下风:

这要是最后没转正,只有一种可能,那就是自己主动跑路了。

好,接下来我们就以《Java 面试指南》里收录的《美团面经同学4 一面》为例,来看看开水团的面试官都喜欢问哪些问题,好做到知彼知己,被面试官吊打,哦不,吊打面试官。

美团同学4 一面面经(30 分钟)内存泄漏怎么排查

内存泄漏是指程序在运行过程中由于未能正确释放已分配的内存,导致内存无法被重用,从而引发内存耗尽等问题。

常用的可视化监控工具有 JConsole、VisualVM、JProfiler、Eclipse Memory Analyzer (MAT)等。

也可以使用 JDK 自带的 jmap、jstack、jstat 等命令行工具来配合内存泄露问题的排查。

严重的内存泄漏往往伴随频繁的 Full GC,所以排查内存泄漏问题时,可以从 Full GC 入手。

第一步,使用 jps -l 查看运行的 Java 进程 ID。

第二步,使用top -p [pid] 查看进程使用 CPU 和内存占用情况。

第三步,使用 top -Hp [pid] 查看进程下的所有线程占用 CPU 和内存情况。

第四步,抓取线程栈:jstack -F 29452 > 29452.txt,可以多抓几次做个对比。

29452为 pid,顺带作为文件名。

看看有没有线程死锁、死循环或长时间等待这些问题。

第五步,可以使用jstat -gcutil [pid] 5000 10 每隔 5 秒输出 GC 信息,输出 10 次,查看 YGC 和 Full GC 次数。

通常会出现 YGC 不增加或增加缓慢,而 Full GC 增加很快。

或使用 jstat -gccause [pid] 5000 输出 GC 摘要信息。

或使用 jmap -heap [pid] 查看堆的摘要信息,关注老年代内存使用是否达到阀值,若达到阀值就会执行 Full GC。

如果发现 Full GC 次数太多,就很大概率存在内存泄漏了。

第六步,生成 dump 文件,然后借助可视化工具分析哪个对象非常多,基本就能定位到问题根源了。

执行命令 jmap -dump:format=b,file=heap.hprof 10025 会输出进程 10025 的堆快照信息,保存到文件 heap.hprof 中。

第七步,可以使用图形化工具分析,如 JDK 自带的 VisualVM,从菜单 > 文件 > 装入 dump 文件。

然后在结果观察内存占用最多的对象,找到内存泄漏的源头。

Spring AOP发生在什么时候

Spring AOP 基于运行时代理机制,这意味着 Spring AOP 是在运行时通过动态代理生成的,而不是在编译时或类加载时生成的。

在 Spring 容器初始化 Bean 的过程中,Spring AOP 会检查 Bean 是否需要应用切面。如果需要,Spring 会为该 Bean 创建一个代理对象,并在代理对象中织入切面逻辑。这一过程发生在 Spring 容器的后处理器(BeanPostProcessor)阶段。

Redis内存中数据丢失怎么解决

当 Redis 中的数据丢失时,可以从 RDB 或者 AOF 中恢复数据。

可以将 RDB 文件或者 AOF 文件复制到 Redis 的数据目录下,然后重启 Redis 服务,Redis 会自动加载数据文件并恢复数据。

Redis 启动时加载数据的流程:

AOF 开启且存在 AOF 文件时,优先加载 AOF 文件。AOF 关闭或者 AOF 文件不存在时,加载 RDB 文件。业界使用哪一种数据持久化,两种持久化方法的优缺点

在 Redis 中,RDB 持久化是通过创建数据的快照来保存数据的,而 AOF 持久化则是通过记录每个写入命令来保存数据的。

两种方式各有优缺点。RDB 持久化的优点是恢复大数据集的速度比较快,但是可能会丢失最后一次快照以后的数据。AOF 持久化的优点是数据的完整性比较高,通常只会丢失一秒的数据,但是对于大数据集,AOF 文件可能会比较大,恢复的速度比较慢。

在 Redis 4.0 版本中,混合持久化模式会在 AOF 重写的时候同时生成一份 RDB 快照,然后将这份快照作为 AOF 文件的一部分,最后再附加新的写入命令。

这样,当需要恢复数据时,Redis 先加载 RDB 文件来恢复到快照时刻的状态,然后应用 RDB 之后记录的 AOF 命令来恢复之后的数据更改,既快又可靠。

Redis跳表

跳表(skiplist)是一种有序的数据结构,它通过在每个节点中维持多个指向其它节点的指针,从而达到快速访问节点的目的。

项目里用 RocketMQ 做削峰,还有什么场景适合消息队列

①、解耦

生产者将消息放入队列,消费者从队列中取出消息,这样一来,生产者和消费者之间就不需要直接通信,生产者只管生产消息,消费者只管消费消息,这样就实现了解耦。

②、异步:

系统可以将那些耗时的任务放在消息队列中异步处理,从而快速响应用户的请求。

平时怎么使用多线程

Java 中创建线程主要有三种方式,分别为继承 Thread 类、实现 Runnable 接口、实现 Callable 接口。

遇到一些比较复杂的业务就会使用线程池。

比如说,在技术派实战项目中,当用户请求首页时,就使用了线程池去加载首页的热门文章、置顶文章、侧边栏、用户登录信息等。

我们封装了一个异步类 AsyncUtil,内部的静态类 CompletableFutureBridge 是通过 CompletableFuture 实现的,其中的 runAsyncWithTimeRecord() 方法就是使用线程池去执行任务的。

public CompletableFutureBridge runAsyncWithTimeRecord(Runnable run, String name) {
    return runAsyncWithTimeRecord(run, name, executorService);
}

核心线程数不够会怎么进行处理

当提交的任务数超过了 corePoolSize,但是小于 maximumPoolSize 时,线程池会创建新的线程来处理任务。

当提交的任务数超过了 maximumPoolSize 时,线程池会根据拒绝策略来处理任务。

饱和策略有哪几种

主要有四种:

分别对应着小二去银行办理业务,被经理“薄纱”了:“我们系统瘫痪了”、“谁叫你来办的你找谁去”、“看你比较急,去队里加个塞”、“今天没办法,不行你看改一天”。

Java面向对象的特点

面向对象编程有三大特性:封装、继承、多态。

封装是指将数据(属性,或者叫字段)和操作数据的方法(行为)捆绑在一起,形成一个独立的对象(类的实例)。

继承允许一个类(子类)继承现有类(父类或者基类)的属性和方法。以提高代码的复用性,建立类之间的层次关系。

同时,子类还可以重写或者扩展从父类继承来的属性和方法,从而实现多态。

多态允许不同类的对象对同一消息做出响应,但表现出不同的行为(即方法的多样性)。

多态其实是一种能力——同一个行为具有不同的表现形式;换句话说就是,执行一段代码,Java 在运行时能根据对象类型的不同产生不同的结果。

策略模式,自己的代码用过什么设计模式

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列的算法,将每个算法封装起来,使得它们可以相互替换。这种模式通常用于实现不同的业务规则或策略,其中每种策略封装了特定的行为或算法。

特别适合用于优化程序中的复杂条件分支语句(if-else),将不同的分支逻辑封装到不同的策略类中,然后通过上下文类来选择不同的策略。

在策略模式中,有三个角色:上下文(Context)、策略接口(Strategy Interface)和具体策略(Concrete Strategy)。

比如说在技术派中,用户可以自由切换 AI 服务,服务端可以通过 if/esle 进行判断,但如果后续需要增加新的 AI 服务,就需要修改代码,这样不够灵活。

因此,我们使用了策略模式,将不同的 AI 服务封装成不同的策略类,通过工厂模式创建不同的 AI 服务实例,从而实现 AI 服务的动态切换。

@Service
public class PaiAiDemoServiceImpl extends AbsChatService {
    @Override
    public AISourceEnum source() {
        return AISourceEnum.PAI_AI;
    }
}
@Slf4j
@Service
public class ChatGptAiServiceImpl extends AbsChatService {
    @Override
    public AISourceEnum source() {
        return AISourceEnum.CHAT_GPT_3_5;
    }
}
@Slf4j
@Service
public class XunFeiAiServiceImpl extends AbsChatService {
    @Override
    public AISourceEnum source() {
        return AISourceEnum.XUN_FEI_AI;
    }
}