面试总结(其他)
面试总结(其他)
LinkedHashMap 如何保证有序
LinkedHashMap继承自HashMap,LinkedHashMap定义了Entry继承自HashMap的Node链表的基础上定义了双向链表来保证顺序,主要是通过双向链表来保证有序的,默认是按照插入顺序,也可以用重载方法的访问顺序来排序
IO/NIO/AIO 模型
IO/BIO(Blocking I/O)
同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。
BIO通信(一请求一应答)模型图如下:
NIO(Non-Blocking I/O)
NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。
NIO线程模型如下:
AIO(Asynchronous non-blocking I/O)
AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会阻塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。
AIO模型:
同步阻塞/同步非阻塞/异步非阻塞是在IO模型中的哪一环节
IO的同步阻塞是在 accept() read()会进行阻塞
1
2
3
4
5
6// IO Server 端
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(8000));// 绑定端口
Socket socket = serverSocket.accept(); // 会阻塞
socket.getInputStream().read(); // 会阻塞NIO的同步非阻塞在 accept() 不会阻塞线程,在select()阶段还是会阻塞
1
2
3
4
5
6
7
8
9// NIO Server 端
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
Selector selector = Selector.open();
serverSocketChannel.bind(new InetSocketAddress(8000)); // 绑定端口
serverSocketChannel.configureBlocking(false); // 设置非阻塞
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // 注册事件
// 阻塞等待客户端Channel
selector.select();
SocketChannel channel = serverSocketChannel.accept(); // 非阻塞AIO的异步非阻塞在accept() 会直接返回,不会等待
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// AIO Server 端
AsynchronousServerSocketChannel socketChannel = AsynchronousServerSocketChannel.open();
socketChannel.bind(new InetSocketAddress(8080)); // 绑定端口
// 非阻塞,等待os回调处理
socketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
public void completed(AsynchronousSocketChannel result, Object attachment) {
// 继续监听下一个请求
socketChannel.accept(attachment, this);
// 处理数据
handler(result);
}
public void failed(Throwable exc, Object attachment) {
System.out.println("服务出现异常:" + exc.getMessage());
}
});
GC Roots 是什么
- 虚拟机栈中引用的对象,比如各线程调用方法堆栈中使用的参数、局部变量、临时变量等
- 方法区中类静态属性引用的对象,比如字符串常量池里的引用和Java类的引用类型静态变量
- 本地方法栈中JNI引用的对象
- Java虚拟机内部的引用,比如:基本数据类型对应的Class对象,以及一些异常对象(NPE、OOM)等,还有系统类加载器
- 所有被同步锁(synchronized关键字)持有的对象
- 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
栈空间如何设置大小,栈空间过大会有什么影响
-Xss128k:设置每个线程的栈大小。JDK5.0以后每个线程栈大小为1M,以前每个线程栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。随着线程栈的大小越大,能够支持越多的方法调用,也即是能够存储更多的栈帧。
线程栈的大小是个双刃剑,如果设置过小,可能会出现栈溢出,特别是在该线程内有递归、大的循环时出现溢出的可能性更大;如果该值设置过大,就有影响到创建栈帧的数量,如果是多线程的应用,就会出现内存溢出的错误.
零拷贝(Zero-Copy)原理
零拷贝(Zero-copy)技术指在计算机执行操作时,CPU 不需要先将数据从一个内存区域复制到另一个内存区域,从而可以减少上下文切换以及 CPU 的拷贝时间。它的作用是在数据报从网络设备到用户程序空间传递的过程中,减少数据拷贝次数,减少系统调用,实现 CPU 的零参与,彻底消除 CPU 在这方面的负载。实现零拷贝用到的最主要技术是 DMA 数据传输技术和内存区域映射技术。
- 零拷贝机制可以减少数据在内核缓冲区和用户进程缓冲区之间反复的 I/O 拷贝操作。
- 零拷贝机制可以减少用户进程地址空间和内核地址空间之间因为上下文切换而带来的 CPU 开销。
CMS 和 G1 的异同
按分代收集来说,CMS是老年代收集器,G1则是混合收集,它开创了混合收集的模式,衡量标准不在是属于哪个分代,而是哪块内存值得收集,哪块内存中存放的垃圾数量最多,回收收益最大来进行收集。
按收集算法来说,CMS收集器是基于标记-清除的垃圾收集器,由于CMS是一款基于“标记-清除”算法实现的收集器,就会造成大量空间碎片产生,如果空间碎片过多时,当需要足够大大连续空间来分配大对象大时候,会不得不提前触发Full GC的情况;而G1从整体来看是基于“标记-整理”算法实现的收集器,从局部上看(两个Region之间)又是基于“标记-复制”算法实现,无论如何,这两种算法在运行期间都不会产生内存空间碎片,垃圾收集完成之后能提供规整的可用内存。
G1 什么时候引发 Full GC
G1 Full GC
的原因一般有:
Mixed GC
赶不上内存分配的速度,只能通过Full GC
来释放内存MetaSpace
不足,对于大量使用反射,动态代理的类,由于动态代理的每个类都会生成一个新的类,同时class
信息会存放在元空间,因此如果元空间不足,G1
会靠Full GC
来扩容元空间,这种情况解决方案就是扩大初始元空间大小。Humongous
分配失败,前面说过G1
分配大对象时,回收是靠Concurrent Marking
或Full GC
,因此如果大对象分配失败,则可能会引发Full GC
说一个最熟悉的垃圾回收算法
可以通过自己熟悉的垃圾回收算法引申一下该算法相应的垃圾收集器实现,比如,标记–复制算法,这是 HotSpot 虚拟机新生代垃圾收集器常用的回收算法,对应的实现有 Serial、Parallel Scavenge,在比如标记–清除算法,对应的垃圾收集器实现有 CMS 等等。
吞量优先和响应时间优先的回收器有哪些
- Parallel Scavenge
- Parallel Old
- G1
怎么判断内存泄漏
讲一下 CMS 的流程
为什么压缩指针超过32G失效
什么是内存泄漏?GC 调优有经验吗?一般出现 GC 问题你怎么解决?
ThreadLocal 有没有内存泄漏问题
G1 两个 Region 不是连续的,而且之间还有可达的引用,我现在要回收另一个怎么处理?
讲一下 JVM 堆内存管理(对象分配过程)
听说过 CMS 的并发预处理和并发可中断预处理吗
到底多大的对象会被直接扔到老年代
JVM虚拟机提供了一个-XX:PretenureSizeThreshold
参数,令大于这个设置值的对象直接在老年代分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制。
所谓的大对象是指,需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组。
注意:PretenureSizeThreshold
参数只对Serial和ParNew两款收集器有效,Parallel Scavenge收集器不认识这个参数,Parallel Scavenge收集器一般并不需要设置。如果遇到必须使用此参数的场合,可以考虑ParNew加CMS的收集器组合。
mysql 原子性和持久性怎么保证
Mysql是利用Innodb的undo log日志来保证原子性的;undo log名为回滚日志,是实现原子性的关键,当事务回滚时能够撤销所有已经成功执行的sql语句,他需要记录你要回滚的相应日志信息redo log
Mysql是利用Innodb的redo log来保证持久性;当做数据修改的时候,不仅在内存中操作,还会在redo log中记录这次操作。当事务提交的时候,会将redo log日志进行刷盘(redo log一部分在内存中,一部分在磁盘上)。当数据库宕机重启的时候,会将redo log中的内容恢复到数据库中,再根据undo log和binlog内容决定回滚数据还是提交数据
Mysql Innodb 和 mylsam 存储引擎区别
区别 | InnoDB | MylSam |
---|---|---|
事务 | 支持 | 不支持 |
外键 | 支持 | 不支持 |
锁的粒度 | 行锁 | 表锁 |
索引 | 聚集索引 | 非聚集索引 |
表的具体行数 | 不提供 | 提供 |
CURD操作 | 适合insert或update场景 | 适合大量select场景 |
索引分类
Innodb 存储引擎的底层数据结构
使用的是B+树
为什么底层使用 B+树不用 B 树
参考另一个面试总结
快速排序的算法原理以及时间复杂度
使用分治法,所有比基准值大的排在右边,小的排在左边,然后两边继续按照这个分治法继续递归,直到完成排序
时间复杂度:O(n*logn)