大厂面试题详解六:Linux&监控&协议&JVM&JMM

237 阅读9分钟

CPU利用率与Load Average的区别

CPU使用率: 一段时间内CPU的使用状况,从这个指标可以看出某一段时间内CPU资源被占用的情况。

Load Average:系统平均负载。某一段时间内,CPU正在处理以及等待CPU处理的进程数的之和。Load Average是从另一个角度来体现CPU的使用状态的。

举个例子:3个医生,2个空闲,1个有10人在排队。此时cpu负载很高,使用率只有33.33%

服务器负载过高问题分析-不是cpu高负载也不是IO负载如何处理(阿里几乎是必考题)

  1. 磁盘使用率是否正常 df -l
  2. 内存使用是否还有空闲 free -m
  3. 服务器流量是否异常变高
  4. JVM内存状态是否异常

TCP/IP四层模型,OSI七层模型

  1. 物理层:通信方式、网线光缆或者wifi信号等
  2. 数据链路层:通讯方式、以太网协议,包含目标mac地址、数据内容等
  3. 网络层:广播到网络中其他设备(IP协议,IP地址、子网掩码)
  4. 传输层:TCP\UDP传输,通过端口号进行连接和通信
  5. 应用层:对传输层数据的解释,HTTP协议
  6. 表示层
  7. 会话层

浏览器请求一个网址的过程

请求网址-> DNS服务器解析IP->路由器转发到目标服务器->服务器解析包内容->代码逻辑处理->返回

主要核心思想就是TCP模型数据传输过程,建立TCP连接,包装4层数据格式,发送数据,服务器解析数据,响应,连接关闭(keepAlive)

TCP 和 UDP 的区别?TCP 数据传输过程中怎么做到可靠的

TCP如何保证数据可靠性

  1. 连接管理:三次握手 四次挥手
  2. 检验和
  3. 确认应答与序列号
  4. 超时重传
  5. 流量控制:根据接受端在ack中回传的 缓冲区空间信息来动态调整发送速度
  6. 拥塞控制

大厂面试题详解六:Linux&监控&协议&JVM&JMM

常用的三个状态是:ESTABLISHED表示正在通信 、TIME_WAIT表示主动关闭、CLOSE_WAIT表示被动关闭(2MSL,一个MSL 30分钟,可配置)。

HTTP HTTPS工作原理

http 1.0,请求网页的html,tcp三次握手建立连接 -> 请求/响应 -> tcp四次挥手断开连接,频繁的建立tcp连接以及释放tcp连接。

http 1.1默认支持长连接,浏览器打开一个网页之后,底层的tcp连接就保持着,不会立马断开。

大厂面试题详解六:Linux&监控&协议&JVM&JMM

  1. 浏览器请求确认加密算法
  2. 服务器返回证书
  3. 浏览器校验证书合法性,生成随机数作为对称加密的密钥,用自己的证书公钥加密,发送给服务器
  4. 服务器用私钥解密获得随机的加密密钥,用这个密钥加密内容,响应回去

加密算法

对称加密:加解密使用同一个密钥3DES DES AES(AES256 3DES 强加密不可破)

非对称加密:公钥加密,私钥解密 RSA D-H

HASH:任意长度二进制映射成固定长度的二进制(hashCode)MD5 SHA系列(SHA256不可破)

负载均衡实现方式

  1. dns解析
  2. http重定向
  3. 反向代理
  4. 链路层负载均衡

线上服务 CPU 很高该怎么做?有哪些措施可以找到问题

  1. 先使用top看下CPU占用高的进程,找出进程的进程ID(pid);top
  2. 根据进程ID(pid)查看是进程的那些线程占用CPU高。top -Hp pid
  3. printf “%x\n” 16872,把线程pid转换成16进制,比如41e8
  4. jstack 43987 | grep ‘0x41e8’ -C5 --color

内存布局

大厂面试题详解六:Linux&监控&协议&JVM&JMM

类加载机制

类加载就是.class字节码文件实例化成Class对象并进行初始化的过程

  1. Load加载,读取类文件产生二进制流
  2. Link链接,验证类型正确语法合理,准备分配内存,解析类引用正确性
  3. Init初始化,执行构造器cinit方法

双亲委派模型

大厂面试题详解六:Linux&监控&协议&JVM&JMM

GC

大厂面试题详解六:Linux&监控&协议&JVM&JMM

什么时候触发YGC?什么时间触发FullGC? 什么条件下,对象会进入老年代?

当Eden区被填满的时候,触发YGC,使用标记-清除算法,没有引用的对象被回收,使用中的S区和Eden存活对象送到未使用的Survivor区(复制算法),如果超过大小,直接进入老年代,S区对象通过-XX:MaxTenuringThreshold配置交换阈值,默认15,超过次数进入老年代,如果老年代满了或者也放不下直接触发FGC(标记-整理),如果依然放不下直接OOM

新生代收集器:

  1. Serial:单线程收集器,垃圾收集时必须STP
  2. Parnew:Serial收集器多线程版本
  3. Parallel Scavenge:复制算法的收集器

老年代收集器:

  1. Serial Old:单线程收集器,标记-整理算法(Serial老年代版本)

  2. Parallel Old:多线程,标记-整理算法(Parallel老年代版本)

  3. CMS:并发收集、低停顿,标记清理算法

  4. 缺点

  5. 并发收集、占用CPU资源,导致程序变慢

  6. 无法处理浮动垃圾(收集过程中产生的,无法在档次收集处理)

  7. 大量空间碎片(默认开启了整理)

  8. G1:JDK 11,未来趋势,内存分成多块,标记-整理-压缩,不会出现内存碎片,Humongous用来存储大对象(超过region50%大小),连续的格子存储

  • 并行、并发,能充分利用CPU多核特性,分代收集
  • 基于标记-整理实现,不会产生内存碎片
  • 可预测的停顿

元空间会发生垃圾回收吗

会,回收无用的常量(没有String引用常量池的常量)和类

无用的类含义:

  • 堆中不存在任何该类实例
  • 加载该类的ClassLoader已经被回收
  • 对Class对象没有引用,无法通过反射访问类的方法

内存使用高于XMX设置内存问题

直接内存:NIO基于DirectByteBuffer可以使用navtive函数直接分配堆外内存

OOM出现的场景,解决方案

1. java堆溢出
2. 内存泄漏 -XX+HeadDumpOnOutOfMemoryError导出内存快照分析

  • 通过内存映像工具确认对象是内存泄漏还是内存溢出
  • 内存溢出 -Xms -Xmx调大堆内存

3. 虚拟机栈和本地方法栈溢出 (创建线程过多)

  • 线程请求深度大于栈深度 StackOverflow -Xss调小 (-Xss 为jvm启动的每个线程分配的内存大小,默认JDK1.4中是256K,JDK1.5+中是1M
  • 动态扩展栈无法申请足够内存,OOM

4. 方法区和运行时常量池溢出

  • JDK1.6运行时常量池在方法区,永久代不够OOM,-XX:PermSize
  • 大量类填满方法区OOM(方法区保存类名、方法描述等)

5. 直接内存溢出 -XX:MaxDirectMemorySize
Dump文件很小,如果使用NIO可以考虑这方面问题

频繁fullgc排查

可能原因

  • 内存分配不合理,导致对象频繁进入老年代,引发FGC
  • 内存泄漏问题,内存里驻留大量对象填满老年代,稍微有对象进入老年代触发FGC
  • 永久代类太多,触发FGC

解决方案

jstat -gc查看内存分配情况,通过survivorRation等推算新生代、老年代大小,CMSInitiaingOccupancyFration比例推算老年代多大会发生FGC。

举例:

  1. 比如知道每分钟3次YGC,Eden区大小300M,说明20秒大概就会产生300M的对象, 每秒大概15M的对象
  2. 再假设每小时2次FGC,30分钟触发一次,根据CMSInitiaingOccupancyFration(例如70,老年代1G),说明30分钟就会产生700M的对象
  3. 继续jstat观察每次YGC后进入老年代的对象大小,和老年代对象触发FGC大小对比,排除是否是因为Eden或者Survivor大小导致,或者是有大对象每次进入老年代打满老年代
  4. 假设确定是经常有大对象产生,jmap dump出内存快照,用mat或者其他工具分析出具体内容,代码对比查找,基本能定位出产生问题原因
  5. 最后,调整各区域大小,或者修改有问题代码

总体步骤大概是一致的

  1. jstat分析内存大小
  2. jmap dump内存文件
  3. 配合内存工具mat或者其他查看是内存泄漏或者其他问题

命令行工具

jps 显示系统内所有HotSpot虚拟机进程

  • jps -l 查看虚拟机进程
  • jps -v 查看虚拟机启动时参数

jstat 收集HotSpot虚拟机各方面运行数据

  • 显示类装载、内存、GC、JIT编译等运行数据
  • jstat -gc vmid 500 10(查询vmid的gc情况,每500ms查询一次,查询10次)

jinfo 显示虚拟机的配置信息

jmap 生成虚拟机的内存转存储快照

  • 获取dump文件、查询finalize执行队列、java堆和永久代信息
  • jmap -dump:format=b,file=eclipse.bin vmid

jhat 分析headdump文件,与jmap搭配使用

jstack 生成虚拟机当前时刻的线程快照

  • jstack -l vmid

内存模型JMM

为了屏蔽硬件和操作系统的内存访问差异,让java程序在各种平台下达到一致的内存访问效果

指令read load use assign store write (lock unlock)

大厂面试题详解六:Linux&监控&协议&JVM&JMM

  • 原子性:上面指令一起成功失败(long 和 double 在 32 位 JVM 中是非原子操作)
  • 有序性:一个线程内的操作指令,都是有序的
  • 可见性:当一个线程修改了共享变量后,其他线程能够立即得知这个修改

volatile原理

强制其他线程重新从主内存加载volatile修饰的字段刷新自己的工作内存

内存屏障保证不会发生指令重排,对volatile修饰的变量,执行写操作的话,JVM会发送一条lock前缀指令给CPU,CPU在计算完之后会立即将这个值写回主内存,同时因为有MESI缓存一致性协议,所以各个CPU都会对总线进行嗅探,自己本地缓存中的数据是否被别人修改,如果发现别人修改了某个缓存的数据,那么CPU就会将自己本地缓存的数据过期掉,然后这个CPU上执行的线程在读取那个变量的时候,就会从主内存重新加载最新的数据了