有懂看heapdump的帮我看下这个是什么原因,导致堆内存在一直加吗

紫川琴秀 2019-03-11 09:02:02

如图,我tomcat启动,只要过了一晚上,内存就能一直加上去,我dump了一份堆信息,麻烦,帮我看下,是哪一个部分出了问题。
看起来最高的百分比是class java/lang/ApplicationShutdownHooks
我使用了rocketmq,里面有一句代码是:
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
producer.shutdown();
}
}));


类的整体代码我也贴一下

package com.qh_goal;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.common.message.Message;


//生产者
public class SmsProducer {
final static DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupSMSResult");
static{
producer.setNamesrvAddr(PublicParameter.ElasticsearchProducer_addr);
producer.setInstanceName("ProducerSMSResult");
producer.setMaxMessageSize(1024*1000*20);
try {
System.out.println("ProducerSMSResult开始加载");
producer.start();
System.out.println("ProducerSMSResult开始成功");
} catch (MQClientException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
public static void pushMsg(String topic,String tag,String key,String _msg) throws MQClientException,
InterruptedException {
/**
* 一个应用创建一个Producer,由应用来维护此对象,可以设置为全局对象或者单例<br>
* 注意:ProducerGroupName需要由应用来保证唯一,一类Producer集合的名称,这类Producer通常发送一类消息,且发送逻辑一致<br>
* ProducerGroup这个概念发送普通的消息时,作用不大,但是发送分布式事务消息时,比较关键,
* 因为服务器会回查这个Group下的任意一个Producer
*/


//nameserver服务

/**
* Producer对象在使用之前必须要调用start初始化,初始化一次即可<br>
* 注意:切记不可以在每次发送消息时,都调用start方法
*/




/**
* 下面这段代码表明一个Producer对象可以发送多个topic,多个tag的消息。
* 注意:send方法是同步调用,只要不抛异常就标识成功。但是发送成功也可会有多种状态,<br>
* 例如消息写入Master成功,但是Slave不成功,这种情况消息属于成功,但是对于个别应用如果对消息可靠性要求极高,<br>
* 需要对这种情况做处理。另外,消息可能会存在发送失败的情况,失败重试由应用来处理。
*/
try {


Message msg = new Message(topic,// topic
tag,// tag
key,// key消息关键词,多个Key用KEY_SEPARATOR隔开(查询消息使用)
_msg.getBytes());// body
SendResult sendResult = null;
try {
sendResult = producer.send(msg);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//System.out.println("111111111111111111111111");
System.out.println(sendResult);


} catch (Exception e) {
e.printStackTrace();
}

/**
* 应用退出时,要调用shutdown来清理资源,关闭网络连接,从MetaQ服务器上注销自己
* 注意:我们建议应用在JBOSS、Tomcat等容器的退出钩子里调用shutdown方法
*/
// producer.shutdown();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
producer.shutdown();
}
}));

}


// public static void main(String[] args) throws MQClientException, InterruptedException {
// Producer.pushMsg("qhcrm","10", "13609560706");
// }
}
...全文
637 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
sjjk 2019-03-11
  • 打赏
  • 举报
回复
没有用过Runtime.getRuntime().addShutdownHook这个方法,但是查了下,说是通过addShutdownHook添加的线程不会立即启动,只有在虚拟机关闭的时候才会去调用这些线程。那么显然,按你的逻辑,每次调用pushMsg推送消息的时候,都会创建一个线程,而这个线程又不会执行,这样就导致了Thread越来也多不停地堆积。我觉得你可以把Runtime.getRuntime().addShutdownHook这段代码放到你的静态代码块里面去。
ZTzhubajie 2019-03-11
  • 打赏
  • 举报
回复
没get到楼主的点,堆内存76%,是程序运行有问题了,继续运行下去会OOM,又或者应用程序有概率不响应客户端的请求?又或者还没有达到GC的阈值? 给的有用的信息太少了。
MiceRice 2019-03-11
  • 打赏
  • 举报
回复
首先注意一个问题:不是每次发送消息都要注册销毁钩子代码! 肉眼直接看了下,感觉你似乎把销毁钩子写进了每次push函数里面去了。 另外,JVM开启GC日志,监控GC日志中FullGC的情况,是否回收后可用内存持续变小,是否GC时间越来越长。 以后可以尽量在系统接近崩溃状态(Full GC高频时),导出HeapDump。

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧