各种类型网站建设口碑好,wordpress 搭建app,南昌网站建设好企业网站,wordpress 遍历 子页面内存泄漏代码前几天#xff0c;我发现了这个小问题#xff1a;该服务器运行了一段时间#xff0c;然后掉下来了。 然后通过启动脚本重新启动#xff0c;整个过程重复进行。 听起来并没有什么坏处#xff0c;因为它虽然对数据造成了重大损失#xff0c;但对业务的重要性并… 内存泄漏代码 前几天我发现了这个小问题该服务器运行了一段时间然后掉下来了。 然后通过启动脚本重新启动整个过程重复进行。 听起来并没有什么坏处因为它虽然对数据造成了重大损失但对业务的重要性并不高所以我决定仔细研究一下找出问题出在哪里。 首先要注意的是服务器通过了所有的单元测试和大量的集成测试。 它在使用测试数据的所有测试环境中都能很好地运行那么生产中出了什么问题 很容易猜到在生产中它的负载可能比测试重或者比设计所允许的负载大因此它耗尽了资源但是什么资源以及在哪里呢 这是一个棘手的问题。 为了演示如何研究此问题首先要做的是编写一些泄漏的示例代码而我将使用Producer Consumer模式进行此操作因为我可以演示它的大问题。 为了演示泄漏的代码1我需要像往常一样需要一个高度人为的方案并且在此方案中假设您在一个将其股票和股票销售记录在数据库中的系统上为股票经纪工作。 订单由一个简单的线程接收并放入队列中。 然后另一个线程从队列中获取订单并将其写入数据库。 的 POJO Order非常简单如下所示 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()方法创建一个新的虚拟订单并将其放置在队列中。 然后它会Hibernate片刻然后再创建下一个订单。 public class OrderFeed implements Runnable { private static Random rand new Random(); private static int id 0; private final BlockingQueueOrder orderQueue; public OrderFeed(BlockingQueueOrder 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 BlockingQueueOrder orderQueue; public OrderRecord(BlockingQueueOrder 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 BlockingQueueOrder orderQueue; public OrderQueueMonitor(BlockingQueueOrder 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 version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beans xmlns:phttp://www.springframework.org/schema/pxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://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-methodstart default-destroy-methoddestroybean idtheQueue classjava.util.concurrent.LinkedBlockingQueue/bean idorderProducer classcom.captaindebug.producerconsumer.problem.OrderRecordconstructor-arg reftheQueue//beanbean idOrderRecorder classcom.captaindebug.producerconsumer.problem.OrderFeedconstructor-arg reftheQueue//beanbean idQueueMonitor classcom.captaindebug.producerconsumer.problem.OrderQueueMonitorconstructor-arg reftheQueue//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.port9010
-Dcom.sun.management.jmxremote.local.onlyfalse
-Dcom.sun.management.jmxremote.authenticatefalse
-Dcom.sun.management.jmxremote.sslfalse …如果您查看使用的堆数量您会发现随着队列变大堆逐渐增加。 如果一千字节的内存泄漏了那么您可能永远也找不到它。 如果一千兆字节的内存泄漏问题将很明显。 因此目前要做的就是坐下来等待一些内存泄漏然后再继续进行下一步调查。 下次再说… 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内存泄漏代码