内存泄漏(memory leak):内存泄漏指程序运行过程中分配内存给临时变量,用完之后却没有被GC回收,始终占用着内存,既不能被使用也不能分配给其他程序,于是就发生了内存泄漏。
内存溢出(out of memory):简单地说内存溢出就是指程序运行过程中申请的内存大于系统能够提供的内存,导致无法申请到足够的内存,于是就发生了内存溢出。
避免内存泄漏:尽早释放无用对象的引用。避免在循环中创建对象。使用字符串处理时避免使用String,应使用StringBuffer。尽量少使用静态变量,因为静态变量存放在永久代,基本不参与垃圾回收。
避免内存溢出的解决方案:第一步,修改JVM启动参数,直接增加内存。第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。第四步,使用内存查看工具动态查看内存使用情况。
Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为6个运行时数据区域。
程序计数器、Java 虚拟机栈、本地方法栈、方法区、运行时常量池
一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其 finalize() 方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
双亲委派模式,即加载器加载类时先把请求委托给自己的父类加载器执行,直到顶层的启动类加载器。父类加载器能够完成加载则成功返回,不能则子类加载器才自己尝试加载。
优点:1. 避免类的重复加载 2. 避免Java的核心API被篡改
年轻代->标记-复制
老年代->标记-清除
分代回收基于两个事实:大部分对象很快就不使用了,还有一部分不会立即无用,但也不会持续很长时间.
GC,即就是 Java 垃圾回收机制。GC 触发的条件有两种,一是程序调用 System.gc 时可以触发,一是系统自身来决定 GC 触发的时机。
从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。当 Eden 区满时,触发 Minor GC。
Full GC 是清理整个堆空间,包括年轻代和老年代。
第一次标记:对于一个没有其他引用的对象,筛选该对象是否有必要执行 finalize() 方法,如果没有执行必要,则意味可直接回收。(筛选依据:是否覆写或执行过 finalize 方法;因为 finalize 方法只能被执行一次)。
第二次标记:如果被筛选判定位有必要执行,则会放入 FQueue 队列,并自动创建一个低优先级的 finalize 线程来执行释放操作。如果在一个对象释放前被其他对象引用,则该对象会被移除 FQueue 队列。
SSM和SpringBoot的区别?
说一下项目SSM迁移到SpringBoot的过程?有难点吗?迁移过程只是代码迁移,还是有额外的业务优化?
项目为什么要升级成SpringBoot呢?
你项目中前端用了JS,有用Vue吗?
如何部署的?有专门的同学部署吗?
Redis在项目中怎么用的?
项目中Gateway和OAuth2.0如何整合的?
SpringBoot常见的注解
RestController和Controller的区别
JVM:
内存泄漏和内存溢出的概念
有哪些垃圾回收算法,
介绍一下它们?
介绍一下老年代
老年代会被回收吗?
MySQL:
MySQL注入?
MySQL如何优化?
基本数据类型
2、静态代码块,什么时候执行
3、jvm了解过没
没
4、垃圾回收机制
没
5、java可变参数
1、说说对Spring Boot的理解
2、对依赖注入的理解
3、对缓存机制的认识;了解Redis的注解嘛?
4、HTTP三次握手和四次挥手
这四个问题是根据我的项目经历来问的。
全程没有问其他,只问了项目,两个面试官。
自我介绍
死磕项目
项目是干嘛的
具体实现了那些功能
MySQL有用到事务吗
用什么框架操作MySQL
MyBatis的分页原理
Nginx了解过吗 原理了解吗
要是项目中出错了 你怎么定位
Vue的部分是你自己写的吗 要你自己搭Vue脚手架你能搭吗
ssm框架有没有自己集成过
MySQL慢语句 怎么定位 怎么解决
用过Linux吗
对Linux了解多少
了解过Tomcat吗
项目是怎么部署的
项目部署用的是jar包还是war包
自我介绍
介绍一下你的第二个项目
String与StringBuffer的区别?
MySQL索引为什么是B+树?
说一说MVC的执行流程?
反射有应用过吗?
SpringBoot有了解过吗?
自我介绍
java面向对象特性
封装的作用
类支持多继承吗
说下抽象类
抽象类和接口的区别
说下项目
说下IO流
python为什么不支持多线程
linux常用命令
数据库常用命令
如何优化数据库
索引如何添加
反射机制了解吗
说下HTML常用标签
hr面:问意向地点、实习时间、家庭情况、对象的工作等,就是看你愿不愿意来浪潮。
二面(视频):
Java 的集合类很多,主要分为两大类,如图:[背下来]
以Buffered开头的缓冲流,用于在读写数据时对数据进行缓存,以减少IO次数;
InputStreamReader、InputStreamWriter是转换流,用于将字节流转换为字符流;
以Object开头的流是对象流,用于实现对象的序列化;
在线程的生命周期中,它要经过新建(New)、就绪(Ready)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。尤其是当线程启动以后,它不可能一直“霸占”着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、就绪之间切换。
在Java中线程通信主要有以下三种方式:
wait()、notify()、notifyAll()
如果线程之间采用synchronized来保证线程安全,则可以利用wait()、notify()、notifyAll()来实现线程通信。这三个方法都不是Thread类中所声明的方法,而是Object类中声明的方法。原因是每个对象都拥有锁,所以让当前线程等待某个对象的锁,当然应该通过这个对象来操作。并且因为当前线程可能会等待多个线程的锁,如果通过线程来操作,就非常复杂了。另外,这三个方法都是本地方法,并且被final修饰,无法被重写。
wait()方法可以让当前线程释放对象锁并进入阻塞状态。notify()方法用于唤醒一个正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后竞争锁,进而得到CPU的执行。notifyAll()用于唤醒所有正在等待相应对象锁的线程,使它们进入就绪队列,以便在当前线程释放锁后竞争锁,进而得到CPU的执行。
每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列。就绪队列存储了已就绪(将要竞争锁)的线程,阻塞队列存储了被阻塞的线程。当一个阻塞线程被唤醒后,才会进入就绪队列,进而等待CPU的调度。反之,当一个线程被wait后,就会进入阻塞队列,等待被唤醒。