为什么在Java 8中连续完整GC

时间:2018-06-12 04:00:23

标签: java garbage-collection

我使用Netty Bootstrap(v3)作为服务器套接字。但是在使用一段时间后,我得到了这个GC日志:

2018-06-12T10:51:18.219-0400: 331664.849: [Full GC (Ergonomics) [PSYoungGen: 129024K->118028K(144896K)] [ParOldGen: 2723411K->2723411K(2723840K)] 2852435K->2841439K(2868736K), [Metaspace: 17983K->17983K(1064960K)], 19.7892397 secs] [Times: user=256.57 sys=0.00, real=19.78 secs] 
2018-06-12T10:51:38.014-0400: 331684.645: [Full GC (Ergonomics) [PSYoungGen: 129024K->118091K(144896K)] [ParOldGen: 2723411K->2723411K(2723840K)] 2852435K->2841503K(2868736K), [Metaspace: 17983K->17983K(1064960K)], 19.6915664 secs] [Times: user=255.44 sys=0.00, real=19.69 secs] 
2018-06-12T10:51:57.716-0400: 331704.347: [Full GC (Ergonomics) [PSYoungGen: 129024K->118166K(144896K)] [ParOldGen: 2723411K->2723411K(2723840K)] 2852435K->2841577K(2868736K), [Metaspace: 17983K->17983K(1064960K)], 23.3087463 secs] [Times: user=300.78 sys=0.00, real=23.30 secs] 
2018-06-12T10:52:21.036-0400: 331727.667: [Full GC (Ergonomics) [PSYoungGen: 129024K->118197K(144896K)] [ParOldGen: 2723411K->2723411K(2723840K)] 2852435K->2841608K(2868736K), [Metaspace: 17983K->17983K(1064960K)], 19.5556922 secs] [Times: user=253.78 sys=0.00, real=19.56 secs] 
2018-06-12T10:52:40.598-0400: 331747.229: [Full GC (Ergonomics) [PSYoungGen: 129024K->118252K(144896K)] [ParOldGen: 2723411K->2723411K(2723840K)] 2852435K->2841664K(2868736K), [Metaspace: 17983K->17983K(1064960K)], 18.9957031 secs] [Times: user=246.53 sys=0.00, real=19.00 secs] 
2018-06-12T10:52:59.601-0400: 331766.232: [Full GC (Ergonomics) [PSYoungGen: 128996K->118259K(144896K)] [ParOldGen: 2723411K->2723411K(2723840K)] 2852408K->2841671K(2868736K), [Metaspace: 17983K->17983K(1064960K)], 19.6780211 secs] [Times: user=255.45 sys=0.00, real=19.68 secs] 

现在,我没有在JVM中设置任何Xms和Xmx参数。

任何人都可以为我分析一下吗?如何优化这种情况?感谢。

更多信息:

我正在使用java:

java版本" 1.8.0_152"

库:

的pom.xml

    <dependency>
        <groupId>com.jolbox</groupId>
        <artifactId>bonecp</artifactId>
        <version>${bonecp.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>commons-configuration</groupId>
        <artifactId>commons-configuration</artifactId>
        <version>1.10</version>
    </dependency>

    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty</artifactId>
        <version>3.10.5.Final</version>
    </dependency>

    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc6</artifactId>
        <version>11.2.0.4</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>

MessageDecoder

@Override
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {

    Message message = null;
    buffer.markReaderIndex();
    ChannelBuffer rawMessage = buffer.copy();

    try {
        loadConfiguration();

        // skip for message start character (#)
        buffer.skipBytes(1);
        byte[] data = null;
        String messageRef;

        // message reference
        ChannelBuffer msgData = readFrame(buffer, messageRefDelimiter);
        messageRef = new String(msgData.array());

        // get data
        msgData = readFrame(buffer, messageDelimiter);
        data = msgData.array();

        message = new Message();
        message.setMessageType(MessageType.Yyyy);
        message.setMessageReference(Long.parseLong(messageRef));
        message.setData(data);

    } catch (Exception e) {

        String msg = new String(rawMessage.array());

        logger.error("Error when decode message {}", msg, e);
        message = null;
    }

    return message;
}

任务管理

static {
    try {
        PropertiesConfiguration config = AppConfig.getPropertiesConfiguration();
        int poolSize    = config.getInt(AppEnv.TASK_POOL_SIZE, AppEnv.TASK_POOL_SIZE_DEFAULT_VALUE);
        int runningTask = config.getInt(AppEnv.TASK_RUNNING, AppEnv.TASK_RUNNING_DEFAULT_VALUE);

        worksQueue = new ArrayBlockingQueue<Runnable>(poolSize);
        executor = new ThreadPoolExecutor(runningTask, runningTask * 2, 10, TimeUnit.SECONDS, worksQueue, executionHandler);

        executor.allowCoreThreadTimeOut(true);

        logger.info("Init TaskManager: poolSize={}, runningTask={}", poolSize, runningTask);
    } catch (AppConfigException e) {
        logger.error("Init TaskManager error", e);
    }
}

/**
 * execute message
 * 
 * @param message
 */
public static void execute(Message message) {
    MessageProcessing messageProcessing = new MessageProcessing(message);
    executor.execute(messageProcessing);
}

MessageProcessing

public void processMessage(Message message) {

    DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");

    String[] data;
    String mes = null;

    try {
        loadConfiguration();
    } catch (Exception e) {
        logger.error("error load configuration", e);
    }

    try {
        mes = new String(message.getData());
        data = mes.split(fieldDelimiter);

        if (data[2].equals("10")) {

            Yyyy10 Yyyy = new Yyyy10();
            Yyyy.message = message.getMessageReference() + "," + mes;
            Yyyy.messageReference = message.getMessageReference();
            Yyyy.imsi = data[0];
            Yyyy.isdn = StringUtil.formatIsdn(data[1]);
            Yyyy.YyyyInformation = Integer.parseInt(data[2]);
            Yyyy.accountProfile = data[3];
            Yyyy.timestamp = df.parse(data[4]);
            Yyyy.refillCount = Integer.parseInt(data[5]);
            Yyyy.mainAmount = Long.parseLong(data[6]);
            Yyyy.bonusAmount = Long.parseLong(data[7]);
            Yyyy.scratchCardNumber = data[8];
            Yyyy.scratchCardProfile = data[9];
            Yyyy.tac = df.parse(data[10] + " 00:00:00");

            //logger.info(Yyyy.toString());

            DbUtil.insertYyyy10(Yyyy);
        }
        else if(data[2].equals("11")) {

            Yyyy11 Yyyy = new Yyyy11();
            Yyyy.message = message.getMessageReference() + "," + mes;
            Yyyy.messageReference = message.getMessageReference();
            Yyyy.imsi = data[0];
            Yyyy.isdn = StringUtil.formatIsdn(data[1]);
            Yyyy.YyyyInformation = Integer.parseInt(data[2]);
            Yyyy.accountProfile = data[3];
            Yyyy.timestamp = df.parse(data[4]);

            //logger.info(Yyyy.toString());

            DbUtil.insertYyyy11(Yyyy);
        } else {
            logger.error("not match Yyyy(10, 11)", message);
        }
    } catch (SQLException e) {

    } catch (Exception e) {
        logger.error("error parse message: {}", message, e);
    } finally {
        try {
            data = null;
            mes = null;
        } catch (Exception e) {}
    }

}

DbUtil

public static void insertYyyy11(Yyyy11 Yyyy) throws SQLException {

    String insertQuery = "INSERT INTO TBL_Yyyy_11(ISDN,MESSAGE_REFERENCE,IMSI,ACCOUNT_PROFILE,TIMESTAMP,MSG_CONTENT) VALUES(?,?,?,?,?,?)";

    try (Connection connection = getConnection(); PreparedStatement preparedStatement = connection.prepareStatement(insertQuery);) {
        preparedStatement.setQueryTimeout(queryTimeout);

        preparedStatement.setString(1, Yyyy.isdn);
        preparedStatement.setLong(2, Yyyy.messageReference);
        preparedStatement.setString(3, Yyyy.imsi);
        preparedStatement.setString(4, Yyyy.accountProfile);
        preparedStatement.setTimestamp(5, DateUtil.toSqlTimestamp(Yyyy.timestamp));
        preparedStatement.setString(6, Yyyy.message);

        preparedStatement.executeUpdate();
    } catch (SQLException e) {
        logger.error("insertYyyy11 error, message: {}", Yyyy, e);
        throw e;
    }
}

线程转储:

有很多RUNNABLE线程

"pool-5-thread-22" #92 prio=5 os_prio=0 tid=0x00007ff5e0044800 nid=0x55ba runnable [0x00007ff6b30ef000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:171)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at oracle.net.ns.Packet.receive(Packet.java:308)
    at oracle.net.ns.DataPacket.receive(DataPacket.java:106)
    at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:324)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:268)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:190)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:107)
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124)
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80)
    at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137)
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:350)
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:227)
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:208)
    at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1046)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1336)
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3613)
    at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3694)
    - locked <0x00000006c6b5b0d0> (a oracle.jdbc.driver.T4CConnection)
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1354)
    at com.jolbox.bonecp.PreparedStatementHandle.executeUpdate(PreparedStatementHandle.java:205)
    at vn.xxx.util.DbUtil.insertYyyy11(DbUtil.java:128)
    at vn.xxx.service.YyyyMessageServiceImpl.processMessage(XXXMessageServiceImpl.java:109)
    at vn.xxx.task.MessageProcessing.run(MessageProcessing.java:33)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

1 个答案:

答案 0 :(得分:0)

最可能的解释是堆几乎已满。如果堆太满,JVM将越来越频繁地运行GC。

鉴于服务器在运行一段时间后才开始执行此操作,最可能的原因是您的应用程序或正在使用的某个库中存在内存泄漏。

假设我的假设是正确的,那么解决问题的方法是使用jhat和内存分析器来尝试识别内存泄漏的来源。

另外几种可能性是你的池中有太多的工作线程(使用太多内存)或你的工作队列严重积压(使用太多内存)或(可能)你使用阻塞队列实际上是在你的(异步?)请求处理中导致积压。

如果您的服务器无法跟上请求率,那么唯一可行的策略就是尽早拒绝......或删除...请求。允许他们积压最终会导致问题。