微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何延迟正确初始化 Java 中的静态数组字段

如何解决如何延迟正确初始化 Java 中的静态数组字段

生成的 Antlr4 词法分析器和解析器有一些内部数据,它们放在堆上,解析后不需要这些数据,我想释放这些数据以清除堆空间并防止内存溢出。我使用惰性初始化器来这样做,然后删除它们。他们中的大多数都很容易做到。

然而,当我这样做时,有一个数组在抱怨。我需要知道这样做的正确习语。我只有一个线程(而且我只使用词法分析器/解析器一次(*除了在测试中,见下文))所以我并不真正关心同步,但我想要有警告/lint免费编译,并且“ findBugs" 不喜欢我使用的代码

这是我尝试的初始代码

public class Lexer;
    protected static DFA[] = null; 
...
    public Lexer(CharStream input) {
       if (_decisionToDFA == null) {
          _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
          for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
              _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i),i);
          }
        }
    }
...
    public void closeLexer() {
       _decisionToDFA = null;
    }

中间尝试进行静态初始化的代码是 FindBugs 抱怨的代码。我尝试了以下方法,但没有帮助。

       if (_decisionToDFA == null) {
          // build it here locally
          DFA _local_decisionToDFA[] = new DFA[_ATN.getNumberOfDecisions()];
          for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
              _local_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i),i);
          }
        _decisionToDFA = _local_decisionToDFA;  // then just move the reference
        }

*以下:

例外是当我运行单元测试时。目前只有 2k 多一点的单元测试,每个测试都会解析一些代码片段,然后遍历生成的解析树并计算一些东西并检查计算是否与正确的语义匹配。

不幸的是,词法分析器和解析器构建的内部数据(例如这些数组和一些缓存等)缓慢累积并最终耗尽所有堆空间,导致接近尾声的测试耗尽内存,这就是为什么我需要释放它们。在生产运行中,每次编译都是一个单独的进程,有自己的地址空间,所以不会有太大的问题。

Description Resource    Path    Location    Type
Incorrect lazy initialization and update of static field Lexer._decisionToDFA in new Lexer(CharStream) [Scary(6),High confidence]  PowerShellLexer.java    /src/main/java/Lexer    line 413    FindBugs Problem (Scary)

解决方法

事实证明,如果将代码放入函数中,似乎可以消除 findBugs 错误消息。

public class Lexer;
    protected static DFA[] = null; 
...
    private DFA[] createDecisionToDFA() {
          // build it here locally
          DFA _local_decisionToDFA[] = new DFA[_ATN.getNumberOfDecisions()];
          for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
              _local_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i),i);
          }
        return _local_decisionToDFA;  // then just move the reference
        }

    public Lexer(CharStream input) {
       if (_decisionToDFA == null) {
          _decisionToDFA = createDecisionToDFA();
        }
    }
...
    public void closeLexer() {
       _decisionToDFA = null;
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。