文档章节

记一次JVM Metaspace溢出排查

浮躁的码农
 浮躁的码农
发布于 04/16 09:17
字数 1309
阅读 15
收藏 3

多图预警!

  • 环境:系统测试(Windows Server/JRE8/tomcat7)
  • 现象:应用运行几天后,出现访问超时,服务器cpu利用率居高不下
  • 问题日志:OutOfMemoryError:MetaSpace
  • 问题分析:
    • 原因分析:MetaSpace是jvm存放类信息的内存空间,发生溢出的可能原因:
      • metaSpace设置过小,不足应用所需
      • 应用metaSpace持续增长,超过metaSpace限制
    • 定位:问题最先从DeviceStatusMonitorTask中报出,而这个定时任务新版本修改了同步设备状态的功能,主要是与vag通信获取设备状态信息。
  • 猜测:
    • 设备状态监控任务中动态生成代理类,导致metaSpace不断消耗
  • 重现:
    • 本地运行应用,添加多个可用设备,缩短task执行间隔
    • 开启Java VisualVM监控
    • 限制Metaspace最大值:-XX:MaxMetaspaceSize=100m

  

  从JVisualVM的监控视图中,我们可以直观的看出每隔一分钟都会出现线程数飙升、类加载数阶梯式增长的情况。

  随着类加载数的增长,Metaspace空间逐步从60M增长到100M,出现内存溢出,导致jvm频繁触发full GC,消耗大量CPU资源。

  •  分析——>找出问题代码

  Task类 run方法代码:

  红框部分为新增代码,具体实现如下:

      主要逻辑是与底层组件通信查询运行状态,然后根据结果更新状态。直接排除DAO操作的嫌疑,抽取与通信部分,整理成单独的测试代码:

步骤: 1. 设置jvm参数 : -verbose:class  打印类加载信息

2. 清理控制台日志,调试代码。

调试过程中,我发现每次循环都会有新的类被加载:

而这些类都是在下面这行代码运行之后加载的。

结合类加载信息以及sendRequest方法的实现,基本确认问题是由JaxbUtil处理xml、JavaBean的相互转换引起。

继续调试分析,发现JAXBContext对象初始化时会动态加载class,而JaxbUtil每次调用都会重新创建一个JAXBContext。

  •  解决方案

问题根因既已找到,解决思路自然清晰明确。

    考虑到jdk中已有JAXB工具类提供xml和javaBean的互转,借鉴源码发现JAXB使用弱引用Cache对象来缓存JAXBContext。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

/**

    * Cache. We don't want to prevent the {@link Cache#type} from GC-ed,

    * hence {@link WeakReference}.

    */

   private static volatile WeakReference<Cache> cache;

 

   /**

    * Obtains the {@link JAXBContext} from the given type,

    * by using the cache if possible.

    *

    * <p>

    * We don't use locks to control access to {@link #cache}, but this code

    * should be thread-safe thanks to the immutable {@link Cache} and {@code volatile}.

    */

   private static <T> JAXBContext getContext(Class<T> type) throws JAXBException {

       WeakReference<Cache> c = cache;

       if(c!=null) {

           Cache d = c.get();

           if(d!=null && d.type==type)

               return d.context;

       }

 

       // overwrite the cache

       Cache d = new Cache(type);

       cache = new WeakReference<Cache>(d);

 

       return d.context;

   }

结合应用的实际场景,上面的实现避免了短时间频繁创建JAXBContext。但是弱引用Cache在无引用的情况下会很快被GC回收,所以每次定时任务都会重新生成context;并且Cache对象只能存储一个context,在定时任务的运行过程中可能由于其他接口通信导致context切换。综上,JAXB的实现也无法满足当前应用的需要。

    没有现成的解决方案,只好自己写一个。

由创建JAXBContext引起问题,那就延长对象的生命周期,减少新建对象。对于相同的Class,可以使用同一个context对象与xml互相转换。由于vag的接口个数有限, 其xml报文格式并不多,因此,维护一个static Map<Class<?>, JAXBContext>来存储context对象占用的内存并不多。考虑到与vag通信属于并发执行,使用ConcurrentHashMap实现保证并发安全。

最终代码如下:

  •  结果验证

将之前的测试代码模拟定时任务略微修改,每隔10s执行一次,重复50次。

开启JVisualVM监视视图,从图中可以明确的看出类装载数在第一次循环时就已接近最大值,后续过程中只加载了极少数量的class,证明这种方案确实可行。

使用修改后的代码运行整个项目,16小时后的监视图像显示:类加载数保持稳定,MetaSpace大小几乎无变化。

  • 总结

    • 排查问题的思路适用于一般的jvm永久代或元空间溢出。
    • 主要采用单例模式的思想解决创建大量复杂对象引起的资源消耗问题。

另外,前段时间还使用-verbose:class 参数排查出Apache CXF生成的webservice客户端重复初始化引起的OOM问题的原因。客户端初始化的过程中也会根据wsdl文件动态生成class并加载,因此,使用CXF客户端代码时,应尽量使用单例模式。

 

本文转载自:https://www.cnblogs.com/tylorliu/p/6978049.html

浮躁的码农

浮躁的码农

粉丝 72
博文 865
码字总数 158123
作品 0
松江
程序员
私信 提问
Metaspace溢出排查过程

庞彤彤 2014年8月加入去哪儿,目前就职于大住宿事业部,主要负责交易运营相关内容。 一、问题 线上的 task 服务出现报警,没有服务者,发现有的机器突然下线了。 第一次出现问题时,发现服务...

Qunar技术沙龙
2018/06/12
0
0
Java 虚拟机16:Metaspace

原文出处:五月的仓颉 被废弃的持久代 想起之前面试的时候有面试官问起过我一个问题:Java 8为什么要废弃持久代即Metaspace的作用。由于当时使用的Java 7且研究重心不在JVM上,一下没有回答上...

五月的仓颉
2018/04/13
0
0
PerfMa给OpenJDK社区提交的第一个Patch

概述 前两天给openjdk gc-dev的email list提交了一个问题,主要是针对Full GC之后,GC日志里Metaspace的大小在GC前后都一直不变的问题,我在邮件里大概也提了下如何修复该问题,以及猜测了下...

你假笨
2018/09/25
0
0
JVM结构 方法区 永久代 元空间

前言 首先明白几个概念:JVM规范和JVM实现,方法区是JVM规范中定义的,永久代是JVM实现(HotSpot)中对于方法区的实现。 Orcale在收到JRockit VM后对JRockit VM和HotSpot的优点做了融合,决定...

Gengry
2017/10/31
0
0
永久代和元空间(Metaspace)

PermGen(永久代) JVM 规范的一种实现 只有 HotSpot 才有 “PermGen space”, 方法区:是JVM的一种规范,存放类信息、常量、静态变量、即时编译器编译后的代码等; 永久代:是HotSpot的一种...

Java搬砖工程师
03/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周一乱弹 —— 满周岁就去挣钱!

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @ tom_tdhzz:一直期待了很久,这是第二次来圆明园,也是特意来这里,只是才发现只有历史现实不在了。#今日歌曲推荐# 分享王晰的单曲《南屏晚...

小小编辑
40分钟前
419
9
解决Structure needs cleaning

简介 今天在同步文件的时候有一个目录突然报错 Structure needs cleaning 百度了一下发现使用xfs_repair可以解决 操作 因为我做的是raid5 ,可能是昨天我重启了机器的缘故,所以我要做的是先...

bboysoulcn
今天
6
0
Dubbo服务暴露与注册

前面的文章中,我们讲解了Dubbo是如何进行配置的属性的初始化的,并且讲到,Dubbo最终会将所有的属性参数都封装为一个URL对象,从而以这个URL对象为基准传递参数。本文则主要讲解Dubbo是如何...

爱宝贝丶
今天
4
0
Leetcode PHP题解--D88 696. Count Binary Substrings

D88 696. Count Binary Substrings 题目链接 696. Count Binary Substrings 题目分析 给定一个01字符串,返回仅用连续的0和1串所能组成的二进制字符串个数。 例如,00110011,就包含0011,0...

skys215
今天
4
0
基础工具类

package com.atguigu.util;import java.sql.Connection;import java.sql.SQLException;import java.util.Properties;import javax.sql.DataSource;import com.alibaba.druid......

architect刘源源
今天
103
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部