调查内存泄漏第1部分–编写泄漏代码

前几天,我发现了这个小问题:该服务器运行了一段时间,然后掉下来了。 然后通过启动脚本重新启动,整个过程重复进行。 这听起来并不那么糟糕,尽管对数据的损失很大,但对业务的重要性并不重要,因此我决定仔细研究一下,找出问题出在哪里。 首先要注意的是,服务器通过了所有的单元测试和大量的集成测试。 它在使用测试数据的所有测试环境中都能很好地运行,那么生产中出了什么问题? 很容易猜到,在生产中,它的负载可能比测试重,或者比设计所允许的负载大,因此它用尽了资源,但是什么资源?在哪里? 这是一个棘手的问题。 屏幕截图2013年11月11日在08.57.22

为了演示如何研究此问题,首先要做的是编写一些泄漏的示例代码,而我将使用Producer Consumer模式来执行此操作,因为我可以演示它的大问题。

为了演示泄漏的代码1,我需要像往常一样需要一个高度人为的方案,在这种情况下,您可以想象您在一个将股票销售量记录在数据库中的系统上的股票经纪人工作。 订单由一个简单的线程接收并放入队列中。 然后,另一个线程从队列中获取订单,并将其写入数据库。 的
Order POJO非常简单,如下所示:

public class Order { private final int id; private final String code; private final int amount; private final double price; private final long time; private final long[] padding; /** * @param id *            The order id * @param code *            The stock code * @param amount *            the number of shares * @param price *            the price of the share * @param time *            the transaction time */ public Order(int id, String code, int amount, double price, long time) { super(); this.id = id; this.code = code; this.amount = amount; this.price = price; this.time = time; // This just makes the Order object bigger so that // the example runs out of heap more quickly. this.padding = new long[3000]; Arrays.fill(padding, 0, padding.length - 1, -2); } public int getId() { return id; } public String getCode() { return code; } public int getAmount() { return amount; } public double getPrice() { return price; } public long getTime() { return time; } }

Order POJO是一个简单的Spring应用程序的一部分,该应用程序具有三个关键抽象,当Spring调用它们的start()方法时,它们会创建一个新线程。

其中第一个是OrderFeed 。 它的run()方法创建一个新的虚拟订单并将其放置在队列中。 然后,它会休眠一会儿,然后再创建下一个订单。

public class OrderFeed implements Runnable { private static Random rand = new Random(); private static int id = 0; private final BlockingQueue<Order> orderQueue; public OrderFeed(BlockingQueue<Order> orderQueue) { this.orderQueue = orderQueue; } /** * Called by Spring after loading the context. Start producing orders */ public void start() { Thread thread = new Thread(this, "Order producer"); thread.start(); } /** The main run loop */ @Override public void run() { while (true) { Order order = createOrder(); orderQueue.add(order); sleep(); } } private Order createOrder() { final String[] stocks = { "BLND.L", "DGE.L", "MKS.L", "PSON.L", "RIO.L", "PRU.L", "LSE.L", "WMH.L" }; int next = rand.nextInt(stocks.length); long now = System.currentTimeMillis(); Order order = new Order(++id, stocks[next], next * 100, next * 10, now); return order; } private void sleep() { try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } 
}

第二类是OrderRecord ,它负责从队列中获取订单并将其写入数据库。 问题在于将订单写入数据库要花费的时间要长得多。 我的recordOrder(…)方法中有1秒的长时间睡眠,这证明了这一点。

public class OrderRecord implements Runnable { private final BlockingQueue<Order> orderQueue; public OrderRecord(BlockingQueue<Order> orderQueue) { this.orderQueue = orderQueue; } public void start() { Thread thread = new Thread(this, "Order Recorder"); thread.start(); } @Override public void run() { while (true) { try { Order order = orderQueue.take(); recordOrder(order); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * Record the order in the database * * This is a dummy method * * @param order *            The order * @throws InterruptedException */ public void recordOrder(Order order) throws InterruptedException { TimeUnit.SECONDS.sleep(1); } }

结果很明显: OrderRecord线程无法跟上,队列将越来越长,直到JVM用完堆空间并OrderRecord为止。 这是生产者-消费者模式的最大问题:消费者必须能够跟上生产者的步伐。

为了证明他的观点,我添加了第三类OrderMonitor ,该类每隔几秒钟打印一次队列大小,以便您可以看到出现问题的地方。

public class OrderQueueMonitor implements Runnable { private final BlockingQueue<Order> orderQueue; public OrderQueueMonitor(BlockingQueue<Order> orderQueue) { this.orderQueue = orderQueue; } public void start() { Thread thread = new Thread(this, "Order Queue Monitor"); thread.start(); } @Override public void run() { while (true) { try { TimeUnit.SECONDS.sleep(2); int size = orderQueue.size(); System.out.println("Queue size is:" + size); } catch (InterruptedException e) { e.printStackTrace(); } } } }

为了完成阵容,我在下面添加了Spring上下文:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd" default-init-method="start" default-destroy-method="destroy"><bean id="theQueue" class="java.util.concurrent.LinkedBlockingQueue"/><bean id="orderProducer" class="com.captaindebug.producerconsumer.problem.OrderRecord"><constructor-arg ref="theQueue"/></bean><bean id="OrderRecorder" class="com.captaindebug.producerconsumer.problem.OrderFeed"><constructor-arg ref="theQueue"/></bean><bean id="QueueMonitor" class="com.captaindebug.producerconsumer.problem.OrderQueueMonitor"><constructor-arg ref="theQueue"/></bean></beans>

下一步是启动泄漏的示例代码。 您可以通过转到以下目录来执行此操作

/<your-path>/git/captaindebug/producer-consumer/target/classes

…然后键入以下命令:

java -cp /path-to/spring-beans-3.2.3.RELEASE.jar:/path-to/spring-context-3.2.3.RELEASE.jar:/path-to/spring-core-3.2.3.RELEASE.jar:/path-to/slf4j-api-1.6.1-javadoc.jar:/path-to/commons-logging-1.1.1.jar:/path-to/spring-expression-3.2.3.RELEASE.jar:. com.captaindebug.producerconsumer.problem.Main

…其中“ path-to ”是您的jar文件的路径

有一两件事,我真的很讨厌关于Java的是,事实上,它是如此难以运行在命令行中的任何程序。 您必须弄清楚什么是类路径,需要设置哪些选项和属性以及什么是主类。 当然,肯定有可能想到一种简单地键入Java programName的方法,并且JVM找出所有内容在哪里,特别是如果我们开始使用约定而不是配置:它有多难?

您还可以通过附加一个简单的jconsole来监视泄漏的应用程序。 如果要远程运行它,则需要在上面的命令行中添加以下选项(选择您自己的端口号):

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9010 
-Dcom.sun.management.jmxremote.local.only=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false

…如果您查看使用的堆数量,您会发现随着队列变大,堆逐渐增加。

屏幕截图2013年11月11日在08.57.47

如果一千字节的内存泄漏了,那么您可能永远也找不到它。 如果一千兆字节的内存泄漏,问题将很明显。 因此,目前要做的只是坐下来等待一些内存泄漏,然后再继续进行下一步调查。 下次再说…

1源代码可以在我在GitHub上的Producer Consumer项目中找到 。

参考: 调查内存泄漏第1部分–在Captain Debug的Blog博客上,由JCG合作伙伴 Roger Hughes 编写泄漏代码 。

翻译自: https://www.javacodegeeks.com/2013/12/investigating-memory-leaks-part-1-writing-leaky-code.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/365554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js正整数正则表达式

function testNumber(){ var yourinputValue$("#yourinputId").val();var reg /^[1-9]\d*$/;alert(reg.test(yourinputValue))} 更多专业前端知识&#xff0c;请上 【猿2048】www.mk2048.com

python打印网页成pdf_vue中将网页打印成pdf

点击下载PDFimport html2canvas from html2canvasimport JSPDF from jspdfexport default {name: home,components: {chead},data () {return {msg: home}},methods: {getPdf: () > {let pdfDom document.querySelector(#home)html2canvas(pdfDom, {onrendered: function (…

[NOIP2013]火柴排队

嘟嘟嘟 首先可以想到&#xff0c;最小距离一定是a中第 i 大的和b中第 i 大的在同一行。 然后先把a&#xff0c;b分别离散化&#xff0c;然后开一个标记数组&#xff0c;map[i]记录a中第 i 小的数在哪一个位置出现&#xff0c;然后对b数组处理一遍。 题中说交换次数&#xff0c;…

.net core 上传文件大小限制 webconfig

<?xml version"1.0" encoding"utf-8"?><configuration> <location path"." inheritInChildApplications"false"> <system.webServer> <handlers> <add name"aspNetCore" path"*&qu…

python标准日期正则表达式_Python 正则表达式验证传统日期

Pure regular exprssion(?x)(?:(?#dd/mm)(3[0-1]|[12][0-9]|0?[0-9])/(1[0-2]|0?[1-9])|(?#mm/dd)(1[0-2]|0?[1-9])/(3[0-1]|[12][0-9]|0?[0-9]))/(?#yy or yyyy)(?:[0-9]{2})?[0-9]{2}Regex with procedural codedef dateCheck(sDate):import redaysinmonth (31, …

Orika:将JAXB对象映射到业务/域对象

这篇文章着眼于使用Orika将JAXB对象映射到业务域对象。 本月初&#xff0c; 我使用基于反射的Dozer讨论 了相同的映射用例 。 在本文中&#xff0c;我假设需要映射相同的示例类&#xff0c;但是它们将使用Orika而不是Dozer进行映射 。 Dozer和Orika旨在解决相同类型的问题&…

es6 语法 (函数扩展)

//函数参数默认值(more值后不能有参数) {function test(x,y world){console.log(默认值,x,y); }test(hello);// hello worldtest(hello,kill); //hello kill } //作用域概念 {let x test;function test2(x,y x){console.log(作用域,x,y);}test2(); // undefined undefined…

python递归必须要有_python如何递归生成树?

好像比較懂你的意思了, 試寫了一個 Tree, 不知道你覺得怎麼樣XDclass Tree:def __init__(self, name):self.name nameself.children {}def __iter__(self):return iter(self.children)def __str__(self):return self.namedef __repr__(self):return Tree("{}").for…

2018秋季C语言学习总结

转载于:https://www.cnblogs.com/noacgnnolife/p/10413255.html

java取非_java运算符 与()、非(~)、或(|)、异或(^)

1.位异或运算(^)运算规则是&#xff1a;两个数转为二进制&#xff0c;然后从高位开始比较&#xff0c;如果相同则为0&#xff0c;不相同则为1。比如&#xff1a;8^11.8转为二进制是1000&#xff0c;11转为二进制是1011.从高位开始比较得到的是&#xff1a;0011.然后二进制转为十…

JOOQ事实:从JPA批注到JOOQ表映射

JOOQ是一个简洁的框架&#xff0c;它解决了我在使用高级动态过滤查询时遇到的一个长期问题。 虽然Hibernate和JPA附带了一个有用的Criteria API&#xff08;我已经使用了很长一段时间&#xff09;&#xff0c;但是使用它们时所能做的却有一些可以理解的限制。 例如&#xff0c;…

解决Charles手机安装SSL证书后,获取到的接口为unknown,且乱码问题

按照正常流程将Charles安装并设置代理后&#xff0c;手机添加完代理并安装SSL证书&#xff0c;尝试抓取接口时&#xff0c;获取到的接口为unknown且返回内容乱码&#xff0c;如下图所示 解决办法&#xff1a; 在Proxy-SSL Proxying Settings-SSL Proxying下添加想要抓取的服务地…

Sum of Even Numbers After Queries

Solution: 转载于:https://www.cnblogs.com/Julietma/p/10414394.html

python的颜色有哪些_Python颜色分类及格式

Python字符串颜色使用下面方式进行修改\033[显示方式;字体色;背景色m 字符串 \033[0m显示方式包括&#xff1a;0 终端默认设置1 高亮显示4 使用下划线5 闪烁7 反白显示8 不可见字体颜色 | 背景颜色 | 颜色描述-------------------------------------------3…

我们甚至没有进行包容性的讨论

科技行业需要更加包容女性和有色人种。 这是关于拥有最大的人才库以吸取卓越的经验。 可悲的是&#xff0c;大多数讨论&#xff0c;甚至是倡导更具包容性的文化讨论&#xff0c;本身都是分裂的。 我们都是个人 我们都是个人。 我们都有自己的优点和缺点。 我们都有自己一生以…

第一次连接mysql失败_MySQL 远程连接失败

解决服务器能登陆 MySQL &#xff0c; 远程账户不能链接问题。(第一次遇见还是挺蒙的)一、 配置文件执行顺序/etc/my.cnf/etc/mysql/my.cnf/usr/etc/my.cnf~/.my.cnf二、用户密码注 &#xff1a; 服务器 tx 云 &#xff0c; OS ubuntu 18.4。1、linux ssh 端口 22 登陆账号密码…

Python学习week7-文件操作

1、文件IO常用操作 # 文件操作命令 2、打开操作open # open(file, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdTrue, openerNone) 创建并打开一个文件test&#xff0c;然后关闭&#xff1b;打开一个文件&#xff0c;返回一个文件对象&#xff08;流对…

将一个实体转换成 Url 参数的形式 ?a=ab=b

function toQueryString(obj) { var ret []; for (var key in obj) { key encodeURIComponent(key); var values obj[key]; if (values && values.constructor Array) { //数组 var queryValues []; for (var i 0, len values.length, value; i < len; i ) …

Spring Boot –现代Java应用程序的基础

Spring Boot是Spring.io中一个相对较新的项目。 其目的是简化创建新的基于Spring Framework的项目&#xff0c;并通过应用一些约定来统一其配置。 这种关于配置的方法约定已经成功地应用于大多数所谓的现代Web框架中&#xff0c;例如Ruby on Rails&#xff0c;Django或Play&…

python qt快速入门_PyQt5快速入门(一)

PyQt5快速入门(一)前言为什么选择PyQt5作为GUI框架?API与Qt一致, 学会PyQt后再使用qt很简单开发迅速, 可视化操作,使用designer快速拖拽布局进行调试可以将文件打包成exe进行发布本节课内容(假设已经掌握python语法)搭建PyQt5环境测试PyQt5环境本节课使用环境python 3.6.6IDLE…