加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – Scanner.findInLine()大量泄漏内存

发布时间:2020-12-14 19:24:46 所属栏目:Java 来源:网络整理
导读:我正在运行一个简单的扫描程序来解析一个字符串,但是我发现如果经常调用,我会得到OutOfMemory错误.此代码作为对象的构造函数的一部分调用,该对象是为字符串数组重复构建的: 编辑:这是更多信息的构造函数;关于Scanner的try-catch之外没有更多的事情发生 pub
我正在运行一个简单的扫描程序来解析一个字符串,但是我发现如果经常调用,我会得到OutOfMemory错误.此代码作为对象的构造函数的一部分调用,该对象是为字符串数组重复构建的:

编辑:这是更多信息的构造函数;关于Scanner的try-catch之外没有更多的事情发生

public Header(String headerText) {
        char[] charArr;
        charArr = headerText.toCharArray();
        // Check that all characters are printable characters
        if (charArr.length > 0 && !commonMethods.isPrint(charArr)) {
            throw new IllegalArgumentException(headerText);
        }
        // Check for header suffix
        Scanner sc = new Scanner(headerText);
        MatchResult res;
        try {
            sc.findInLine("(D*[a-zA-Z]+)(d*)(D*)");
            res = sc.match();
        } finally {
            sc.close();
        }

        if (res.group(1) == null || res.group(1).isEmpty()) {
            throw new IllegalArgumentException("Missing header keyword found");     // Empty header to store
        } else {
            mnemonic = res.group(1).toLowerCase();                            // Store header
        }
        if (res.group(2) == null || res.group(2).isEmpty()) {
            suffix = -1;
        } else {
            try {
                suffix = Integer.parseInt(res.group(2));       // Store suffix if it exists
            }  catch (NumberFormatException e) {
                throw new NumberFormatException(headerText);
            }
        }
        if (res.group(3) == null || res.group(3).isEmpty()) {
            isQuery= false;
        } else {
            if (res.group(3).equals("?")) {
                isQuery = true;
            } else {
                throw new IllegalArgumentException(headerText);
            }
        }

        // If command was of the form *ABC,reject suffixes and prefixes
        if (mnemonic.contains("*") 
                && suffix != -1) {
            throw new IllegalArgumentException(headerText);
        }
    }

分析器内存快照显示Scanner.findInLine()的读取(Char)方法在操作期间分配大量内存,因为我扫描了几十万个字符串;几秒钟后它已经分配超过38MB.

我认为在构造函数中使用它之后在扫描程序上调用close()会标记要由GC清除的旧对象,但不知何故它仍然存在并且read方法在填充堆之前累积了数十亿字节的数据.

任何人都能指出我正确的方向吗?

解决方法

您还没有发布所有代码,但鉴于您正在重复扫描相同的正则表达式,预先编译静态模式并将其用于扫描程序的查找会更有效:
static Pattern p = Pattern.compile("(D*[a-zA-Z]+)(d*)(D*)");

并在构造函数中:

sc.findInLine(p);

这可能是也可能不是OOM问题的根源,但它肯定会使您的解析速度更快.

相关:java.util.regex – importance of Pattern.compile()?

更新:在您发布更多代码后,我会看到其他一些问题.如果你反复调用这个构造函数,这意味着你可能预先标记或分解输入.为什么要创建一个新的Scanner来解析每一行?它们是昂贵的;如果可能,您应该使用相同的扫描程序来解析整个文件.使用具有预编译模式的一个扫描程序将比您现在正在执行的操作快得多,这将为您要解析的每一行创建一个新的扫描程序和一个新模式.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读