1.java中出现了异常的线程需要如何排查?
在线程运行的过程中,出现了某些线程异常处理方法:
- top命令 可以动态查看进程的ID。然后针对具体的异常java进程,使用top -H -p 进程号,即可动态的查看具体的进程对应所在的每个线程的动态变化情况,利用jstack命令查看相关的线程信息进行排查。
- ps命令 可以使用ps -aux 来查看具体的每个进程的实际应用占用资源情况。结合awk、sort 可以快速定位。实例:ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head 。
2. hashmap多线程下出现的问题?
1.当多线程同时put值的时候,若发生hash碰撞,可能多个元素都落在链表的头部,从而造成元素覆盖(hashcode相同而eques值不同的元素)
例如:线程A put一个元素a ,线程B put一个元素b,a,b 发生hansh碰撞,本应该在map是链表的形式存在,但是可能线程A和线程B同时put到链表的第一个位置,从而后来者覆盖前者元素造成元素丢失。
2.put 造成链表形成闭环,get的时候出现死循环(jdk8已经解决该问题),该情况是出现在多线线程操作map扩容时会发生。
3.hashmap初始化的容量不为2的n次方会怎样?
容量为2的n次方的优点:
- 长度是2的n次幂是 取模可以转换成按位与运算 效率更高
- 扩容的时候 这样的长度设置更高效 扩展也总是2次幂的 这样的话 元素位置要么在原位 要么移动2次幂
如果初始化不为2的n次方,会如何?
如不是2的N次方那么在第一次put 元素的时候也会自动把容量设置为比传入参数大的最小的2的N次方,并不是你指定的这个值。
static final int tableSizeFor(int cap) {
int n = cap - 1;
//移位运算
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
4. 数据库大表不停机如何加字段
- 直接添加字段:如果该表读写不频繁,数据量较小(通常1G以内或百万以内),直接添加即可
- 使用pt_osc工具添加:如果表较大 但是读写不是太大,且想尽量不影响原表的读写,可以用percona tools进行添加,相当于新建一张添加了字段的新表,再将原表的数据复制到新表中,复制历史数据期间的数据也会同步至新表,最后删除原表,将新表重命名为原表表名,实现字段添加 。
- 先在从库添加 再进行主从切换: 如果一张表数据量大且是热表(读写特别频繁),则可以考虑先在从库添加,再进行主从切换,切换后再将其他几个节点上添加字段
5.ArrayList的扩容机制
ArrayList的底层是一个动态数组,ArrayList首先会对传进来的初始化参数initalCapacity进行判断
- 如果参数等于0,则将数组初始化为一个空数组,
- 如果不等于0,将数组初始化为一个容量为10的数组。
当数组的大小大于初始容量的时候(比如初始为10,当添加第11个元素的时候),就会进行扩容,新的容量为旧的容量的1.5倍。
6. jvm频繁full gc怎么处理,如何调参?
GC两种类型:一种是部分收集(Partial GC),一种是整堆回收(Full GC)。
(1)部分收集:
- 新生代收集(Minor GC / Young GC): 只是新生代(Eden \ S0,S1)的垃圾收集
- 老年代收集(Major GC / Old GC): 只是老年代的垃圾收集
- 混合收集(Mixed GC): 收集整个新生代以及部分老年代的垃圾收集
(2)整堆收集(Full GC): 收集整个Java堆和方法区的垃圾收集
6.1出现频繁gc的原因:
(1)System.gc()方法的调用。
此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC
来禁止RMI调用System.gc。
(2)老年代空间不足。
老年代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出如下错误:java.lang.OutOfMemoryError: Java heap space
为避免以上两种状况引起的Full GC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。
(3)元空间空间不足
JVM规范中运行时数据区域中的方法区,在HotSpot虚拟机中又被习惯称为永生代或者永生区,Permanet Generation中存放的为一些class的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息:java.lang.OutOfMemoryError: PermGen space
为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。
(4)堆中分配很大的对象
年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发JVM进行Full GC。
为了解决这个问题,CMS垃圾收集器提供了一个可配置的参数,即-XX:+UseCMSCompactAtFullCollection
开关参数,用于在“享受”完Full GC服务之后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但提顿时间不得不变长了,JVM设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction
,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的。
6.2 排查频繁gc
1.查看项目启动的GC命令,检查是否有异常指令:
比如有些同事可能对于GC参数理解的不是很透彻,本来想着优化的目的,但是却起了反作用。
2.查看yonggc的频率:
这一步主要是为了查看是否存在递归或者频繁创建对象,并且频繁回收,导致yonggc频繁,进而导致fullgc频繁,如果ygc频繁,则需要检查代码中是否存在不符合规范的地方了。
3.查看每一次fullgc的回收率:
如果ygc正常,但是fullgc频繁,那么这一步是为了查看是否存在内存泄漏,定位是否存在对象的长时间引用,内存泄露会占用大量内存空间,且无法正常回收,导致fullgc越发频繁,且stw时间越发长。
4.查看堆栈情况,找到占用内存较大的对象:
查看当前的堆栈信息,如果有监控工具可以直接使用,没有的话就使用JDK自带的一些命令,找到是否存在大对象的频繁创建。
5.查看元数据区的回收频率:
Metadata GC Threshold,当我们发现以上情况都不存在,然后dump一下看看是否发生元数据区导致的频繁fullgc,当然这种情况很少见,但是可以定位排除一下。