【问题标题】:How do I fix a memory leak in java [duplicate]如何修复java中的内存泄漏[重复]
【发布时间】:2015-09-29 19:54:01
【问题描述】:

我目前正在尝试编写一个程序,从 Steam 获取字符串化的 json 对象,并使用该对象来确定我是否可以在 Steam 市场上购买商品。

它有效,但是我似乎遇到了大量的内存泄漏,我不知道如何解决这个问题,因为我是一个初学者程序员。代码如下:

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;


public class SteamMarketAlert {

    @SuppressWarnings("unused")
    private JAlertWindow alert;
    private URL jsonUrl;
    private float walletValue;
    private boolean itemBuyable;

    public SteamMarketAlert(URL itemUrl, float walletValue)
    {
        this.itemBuyable = false;
        this.jsonUrl = getJSONurl(itemUrl);
        this.walletValue = walletValue;
    }

    private URL getJSONurl(URL itemUrl)
    {
        String jsonString = itemUrl.toString();

        String firstPart = jsonString.substring(0, jsonString.indexOf("market/") + "market/".length());

        String appid = jsonString.split("/")[5];
        String marketHashName = jsonString.split("/")[6];

        String secondPart = "priceoverview/?currency=2&appid=" + appid + "&market_hash_name=" + marketHashName;

        try {
            return new URL(firstPart + secondPart);
        } catch (MalformedURLException e) {
            System.err.println("Failed to create json url");
            return null;
        }

    }

    public void checkMarket()
    {
        Thread thread = new Thread(){
            @Override
            public void run(){
                try {
                    while(!itemBuyable)
                    {
                        sleep(5000);                        
                        if(isBuyable(getPagehtml()))
                            itemBuyable = true;
                    }
                    alert = new JAlertWindow();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }   
        };

        thread.start();


    }

    private boolean isBuyable(String pagehtml)
    {
        int firstIndex = pagehtml.indexOf(";") +1;


        float marketValue = Float.parseFloat(pagehtml.substring(firstIndex, firstIndex + pagehtml.substring(firstIndex, pagehtml.length()).indexOf("\"")));

        return (marketValue <= walletValue)? true:false;
    }

    private String getPagehtml(){

        try(Scanner scanner = new Scanner(jsonUrl.openConnection().getInputStream())) {

            scanner.useDelimiter("\\Z");
            return scanner.next();
        } catch (IOException e) {               
            e.printStackTrace();
            return null;
        }

    }

    public static void main(String[] args)
    {
        try {
            float walletValue =  82.64f;
            URL itemUrl = new     URL("http://steamcommunity.com/market/listings/730/StatTrak%E2%84%A2%20P90%20%7C%20Asiimov%20%28Factory%20New%29");
            SteamMarketAlert sma = new SteamMarketAlert(itemUrl,walletValue);
            sma.checkMarket();


        } catch (MalformedURLException e) {

            e.printStackTrace();
        }

    }
}

我已将问题缩小到 checkMarket() 方法。但是,我似乎无法弄清楚发生了什么。您能否指出我如何解决这个问题(并可能指出我的代码中的所有缺陷),注意 JAlertWindow 对象只显示一个带有“CAN BUY”的 JFrame - 没什么特别的。

编辑:我在发布后更新了代码,用户告诉我 try-with-resource 块存在。感谢所有帮助我了解 Java 垃圾收集工作原理的人。 :)!

【问题讨论】:

  • 一方面,不需要在线程中的while 循环之外声明html。实际上,您根本不需要StringBuilder,只需从getPagehtml 返回scanner.next() 的值。并不是说这会对内存泄漏产生太大影响,只是有点笨拙。
  • 请描述“内存泄漏”的确切含义以及如何证明它的存在。
  • 好吧,当我将它导出到 .jar 文件并启动 jar 时,它在任务管理器中运行时,内存值会随着时间的推移而上升,所以从大约 12,000 K 开始,然后在大约 10 分钟内达到大约 30,000 K ......并且继续上升:P。这就是我所说的内存泄漏。
  • @AndyTurner 如果我在扫描仪仍处于打开状态时返回值,我该如何关闭扫描仪?我的意思是“返回scanner.next():”肯定会在不关闭扫描仪的情况下让我脱离getPagehtml()方法吗?我的印象是我必须关闭扫描仪。
  • 如果您没有收到OutOfMemoryException,您没有问题。

标签: java memory-leaks


【解决方案1】:

在您收到 OutOfMemoryException 或看到持续的垃圾回收之前,这可能不是 Java 中的内存泄漏。

在 10 分钟内使用 18MB 看起来不像是内存泄漏,这正是 Java 的工作原理。如果您真的想确定,可以打开详细 GC 并查看它收集的频率,但我认为您还没有真正的问题。

【讨论】:

  • 谢谢,我刚刚看到内存不断攀升,并认为这是一个问题 - 特别是考虑到我要运行一段时间。
【解决方案2】:

您正在获取 html 页面,因此每次获取时都必须在内存中分配一些对象(字符串等)。稍后(一旦不再使用)这些对象将被删除并且内存被 GC 标记为空闲。

抱歉,解释太简单了。如果您想了解更多信息,请阅读有关 java GC、堆结构等方面的信息。

【讨论】:

    【解决方案3】:

    为什么不运行 Java 分析器?我推荐使用YourKit。我经常使用它来查找服务器上任何内存泄漏的原因。它也非常适合连接以删除应用程序;你应该玩弄它。

    这是他们自己的关于如何查找内存泄漏的视频的链接; Link

    如果您需要更多帮助,您应该快速阅读他们的docs

    【讨论】:

    • 这真的是评论,而不是答案。多一点代表,you will be able to post comments
    • 是的,我从来没有拒绝过你所说的任何事情,如果我以后找不到内存泄漏,我会记住这个评论:)。感谢您的评论。 (我问的主要问题不是发现泄漏,而是更多关于如何修改代码以防止泄漏)
    猜你喜欢
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 2012-01-12
    • 2018-05-09
    • 2018-07-12
    相关资源
    最近更新 更多