因为第二部分内容过于冗长,为了避免引起阅读反感,所以后续案例将在此部分补充!
三、jvm调优(后续)
实战案例分析、定位cpu飙升、OOM问题
(3)案例三,测试代码如下:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class T15_FullGC_Problem03 {
public static Map<String,String> allJurisdictionMap() {
Map<String,String> map = new HashMap();
map.put("1","权限1");
map.put("2","权限2");
map.put("3","权限3");
map.put("4","权限4");
return map;
}
public static void main(String[] args) {
//模拟登陆人信息
Map<String,String> personCodeMap = new HashMap<>();
getPersonJurisdictionMap(T15_FullGC_Problem03.allJurisdictionMap(),personCodeMap);
}
/**
* 返回登陆人对应的权限信息
* @param allJurisdictionMap
* @param personCodeMap
* @return
*/
private static Map<String,String> getPersonJurisdictionMap(Map<String,String> allJurisdictionMap,Map<String,String> personCodeMap){
Map<String,String> map2 = new HashMap(allJurisdictionMap);
Iterator<String> iterator = map2.keySet().iterator();
while (iterator.hasNext()){
for (String key : personCodeMap.keySet()){
if (iterator.next().equals(key)){
personCodeMap.put(key,map2.get(key));
}
}
}
return personCodeMap;
}
}
其主要功能就是根据公司的全部权限信息,筛选出当前登陆人的信息!
javac 编译后运行程序,使用top命令观察状态:
可以看到cpu已经100%了,通过arthas工具attach此进程,并使用thread命令观察:
发现线程1的cup使用率已经高达99%,然后我们接着使用thread命令:thread 1 (数字表示线程id),定位此线程的栈信息:
通过以上信息我们发现问题出在:getPersonJurisdictionMap方法!
下面我们来分析这段问题代码!
(1)由于传入方法的personCodeMap集合为空,所以导致for循环的代码块不会被执行;
(2)iterator.hasNext()方法不会使迭代器的指针发生偏移,所以最终发生了死循环;
下面是优化后的代码:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class T15_FullGC_Problem03 {
public static Map<String,String> allJurisdictionMap() {
Map<String,String> map = new HashMap();
map.put("1","权限1");
map.put("2","权限2");
map.put("3","权限3");
map.put("4","权限4");
return map;
}
public static void main(String[] args) {
//模拟登陆人信息
Map<String,String> personCodeMap = new HashMap<>();
getPersonJurisdictionMap(T15_FullGC_Problem03.allJurisdictionMap(),personCodeMap);
}
/**
* 返回登陆人对应的权限信息
* @param allJurisdictionMap
* @param personCodeMap
* @return
*/
private static Map<String,String> getPersonJurisdictionMap(Map<String,String> allJurisdictionMap,Map<String,String> personCodeMap){
Map<String,String> map2 = new HashMap(allJurisdictionMap);
Iterator<String> iterator = map2.keySet().iterator();
while (iterator.hasNext()){
String param = iterator.next();
for (String key : personCodeMap.keySet()){
if (param.equals(key)){
personCodeMap.put(key,map2.get(key));
}
}
}
return personCodeMap;
}
}
代码分析:
这里我们在每次迭代的时候直接获取元素 String param = iterator.next(); ,然后进行比较!这样即使personCodeMap为空,在每次迭代时iterator.next()都会使指针发生偏移!因此不会发生死循环!
(4)前面的案例都是在cpu升高(程序没死之前),没有发生OOM时的定位方法,当程序发生OOM死亡后,我们如何根据此次的OOM信息定位问题呢!
java -Xms200M -Xmx200M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/taosun/logs/ -Xloggc:/opt/taosun/logs/tao-sun-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause T15_FullGC_Problem01
根据程序启动时指定的OOM 的log目录,查看本次日志信息:
hprof结尾的文件都是OOM时产生的dump文件(案例一OOM时的log文件,我这里运行的次数比较多),下载对应的文件,使用jdk自带的jvisualvm工具进行dump文件的分析!
1.选择文件----》装入
2.找到自己下载的文件目录,文件类型选择堆Dump,点击打开倒入文件!
3.文件装载完成后,将会显示如下基本信息、线程信息等!
4.选择后面的类信息,即可查看本次oom所产生的实例对象信息
左边是对象实例名称,右边是对象实例数、大小等信息!
此处的信息和我们使用jmap命令时一样,所以这里就不再做分析了!
ok!至此jvm调优相关的内容已经全部结束!如对您有帮助,转载时请标明出处!谢谢!