日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内存泄漏代码_调查内存泄漏第1部分–编写泄漏代码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

內存泄漏代碼

前幾天,我發現了這個小問題:該服務器運行了一段時間,然后掉下來了。 然后通過啟動腳本重新啟動,整個過程重復進行。 聽起來并沒有什么壞處,因為它雖然對數據造成了重大損失,但對業務的重要性并不高,所以我決定仔細研究一下,找出問題出在哪里。 首先要注意的是,服務器通過了所有的單元測試和大量的集成測試。 它在使用測試數據的所有測試環境中都能很好地運行,那么生產中出了什么問題? 很容易猜到,在生產中,它的負載可能比測試重,或者比設計所允許的負載大,因此它耗盡了資源,但是什么資源以及在哪里呢? 這是一個棘手的問題。

為了演示如何研究此問題,首先要做的是編寫一些泄漏的示例代碼,而我將使用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 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

…如果您查看使用的堆數量,您會發現隨著隊列變大,堆逐漸增加。

如果一千字節的內存泄漏了,那么您可能永遠也找不到它。 如果一千兆字節的內存泄漏,問題將很明顯。 因此,目前要做的就是坐下來等待一些內存泄漏,然后再繼續進行下一步調查。 下次再說…

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

內存泄漏代碼

總結

以上是生活随笔為你收集整理的内存泄漏代码_调查内存泄漏第1部分–编写泄漏代码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。