简体   繁体   中英

How to lazy correctly initialize a static array field in Java

The generated Antlr4 lexers and parsers have some internal data they put on the heap which isn't necessary after parsing that I want to free up to clear heap space and prevent memory overflows. I am using lazy initializers to do so and then delete them afterward. Most of them were easy to do.

However there is an array that is complaining when I do so. I need to know the correct idiom for doing it. I only have one thread (and I only use the lexer/parser once (*except for in testing, see below)) so I'm not really concerned about synchronization, but I would like to have warning/lint free compiles, and "findBugs" doesn't like the code I am using.

Here is the initial code I tried:

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;
    }

The code in the middle which attempts to do the static initialization is the code FindBugs complains about. I tried the following but it didn't help.

       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
        }

*below:

The exception is when I am running unit tests. The unit tests of which there are currently just a little over 2k, each parse some fragment of code and the walk the generated parse tree and compute something and check that the computation matches the proper semantics.

Unfortunately, the internal data (eg these arrays and some caches, etc.) that the lexer and parser build to do so, slowly accumulates and eventually uses up all the heap space causing the tests near the end to run out of memory, which is why I need to free them. In production runs, each compilation is a separate process with its own address space, so it wouldn't be as much an issue.

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)

It turns out if you put the code into a function, that seems to quiet the findBugs error message.

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;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM