JVM频繁FullGC又不会OOM怎么定位大对象的使用位置

10 篇文章 1 订阅
8 篇文章 0 订阅
1.把堆内存dump下载

jps //查看pid
jmap -dump:format=b,file=heap.1 pid //不进行垃圾回收直接dump

jmap -dump:live,format=b,file=heap.2 pid //进行fgc垃圾回收在进行dump


2.使用java VisualVM(lib目录下jdk8自带)导入dump文件

导入后的截图

2.分析下面1.5g数组在哪里使用

3.双击byte[]看到的页面如下

 

 数组不是1.5g吗上面只是定位了1g的使用位置那么还有500m在哪里使用了呢我们继续定位

注意!
如果发现某个对象在线程中显示按钮是灰色的表示该对象的线程或者方法已经执行完毕
是无非定位到该对象,解决办法在方法中进行睡眠然后dump文件
此时dump的文件对象是可以获取使用位置具体代码如下

1.解决方案

jvm中发现一个Goods对象有10万个对象怎么定位,可以在构造方法判断这个对象创建==10万个
,此时是dump文件的最佳时间
       private  static int createNum;
    public  Customer() {
        private  static int createNum;
    @Transient
    Logger logger = LoggerFactory.getLogger(Customer.class);
    public  Customer() {
        synchronized (Customer.class){
            createNum++;
        }
            StackTraceUtil.updateStackTrace();
            if(createNum==100000){
                try {
                    String path = AutoDumpUtil.doDump(this);
                    logger.warn("发现有"+createNum+"个"+Customer.class+"对象,已自动dump文件,请检查是否异常,path="+path);
                    logger.warn(StackTraceUtil.getStackTrace());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    }

    }

工具类1
public class AutoDumpUtil {
    private static Logger logger = LoggerFactory.getLogger(AutoDumpUtil.class);

    /**
     *
     * @param o 什么都不做为了确保能获取o对象的GCRoot必须传入
     * @throws Exception
     */
    public static   String  doDump(Object o) throws Exception {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        String name = runtimeMXBean.getName();
        int index = name.indexOf("@");
        String path="";
        if (index != -1) {
            int pid = Integer.parseInt(name.substring(0, index));
            Runtime runtime = Runtime.getRuntime();
            long start = System.currentTimeMillis();

            char separatorChar = File.separatorChar;
            path="f:"+separatorChar+"dev"+separatorChar+"autoDump."+pid+" ";
            String cmd="jmap -dump:format=b,file="+path+pid;
            Process exec = runtime.exec(cmd);
            //等待命令执行完
            exec.waitFor();
            long end = System.currentTimeMillis();
            logger.warn("autoDump."+pid+"文件成功,耗时:"+(end-start)+"ms");
        }
        return path;
    }
}

工具类2
public class StackTraceUtil {
    private static Map<String,Integer>  map = new ConcurrentHashMap<>();

    public static  void updateStackTrace(){
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        String stack="class=["+stackTrace[3].getClassName()+"] methodName=["+stackTrace[3].getMethodName()+"] line=["+stackTrace[3].getLineNumber()+"]";
        if(map.containsKey(stack)){
            Integer count = map.get(stack);
            map.put(stack,++count);
        }else{
            map.put(stack,1);
        }


    }

    public static String  getStackTrace(){
        final String[] result = {""};

        map.forEach((k,v)->{
            result[0] +=k+",调用次数="+v+"\r\n";
        });

        return result[0];
    }
}

2.看项目的调用结构,找出Customer占用内存比较大的位置,这里可以使用StackTraceUtil 定位,也可以自己打开dump文件分析定位

 

3.打印的日志,根据日志的提示找到大对象的位置比如下面有三个地方创建了Customer大量的对象,我们就以创建最多的7万次分析

class=[com.yujie.service.impl.OrderCustomerImpl] methodName=[save] line=[20],意思是OrderCustomerImpl类save方法第20行创建了7万次对象
2022-06-05 10:47:30.826 [Thread-13] WARN  com.yujie.utils.AutoDumpUtil - autoDump.10872文件成功,耗时:2583ms
2022-06-05 10:47:30.826 [Thread-13] WARN  com.yujie.model.Customer - 发现有100000个class com.yujie.model.Customer对象,已自动dump文件,请检查是否异常,path=f:\dev\autoDump.10872
2022-06-05 10:47:30.827 [Thread-13] WARN  com.yujie.model.Customer - class=[com.yujie.service.impl.OrderCustomerImpl] methodName=[save] line=[20],调用次数=70000
class=[sun.reflect.NativeConstructorAccessorImpl] methodName=[newInstance0] line=[-2],调用次数=1
class=[com.yujie.service.impl.C] methodName=[save] line=[19],调用次数=19999
class=[com.yujie.service.impl.B] methodName=[save] line=[19],调用次数=10000

到此完毕谢谢大家支持

 

  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值