stanfordnlp/CoreNLP · warning

Cached annotator will never GC -- this can cause OOM…

Error message

Cached annotator will never GC -- this can cause OOM exceptions!

What it means

AnnotatorPool's CachedAnnotator constructor warns when the wrapped Lazy<Annotator> is not a caching Lazy. A non-caching Lazy holds only a supplier, so every annotation request may rebuild the annotator, and the constructed annotator instance is strongly held without the cache mechanism that allows garbage collection — leading to unbounded memory growth and potential OutOfMemoryError.

Solutions

  1. Wrap the annotator supplier with Lazy.cache(...) (or use Lazy.of followed by .cache()) so the pool's caching/GC behavior applies.
  2. If the annotator is stateless and cheap, keep the non-caching lazy but be aware it will be rebuilt per request; better to cache it anyway.
  3. In long-running services, avoid re-creating AnnotatorPools; reuse a single cached pool and monitor heap usage.

Example fix

// before
AnnotatorPool.AnnotationFactory factory = (signature, props) ->
    new AnnotatorPool.CachedAnnotator(signature, Lazy.of(() -> new MyAnnotator(props)));

// after
AnnotatorPool.AnnotationFactory factory = (signature, props) ->
    new AnnotatorPool.CachedAnnotator(signature, Lazy.cache(() -> new MyAnnotator(props)));
Defensive patterns

Strategy: validation

Validate before calling

// Only construct CachedAnnotator with a caching Lazy
Lazy<Annotator> lazy = Lazy.cache(() -> new MyAnnotator(props));
if (!lazy.isCache()) {
  throw new IllegalArgumentException("Annotator lazy must be caching to avoid GC leak");
}

Prevention

When it happens

Trigger: Constructing a CachedAnnotator with Lazy.of(...) (non-caching) instead of Lazy.cache(...), typically when registering a custom annotator into an AnnotatorPool.

Common situations: Custom pipeline code that plugs annotators into Stanford CoreNLP's AnnotatorPool with a hand-rolled Lazy wrapper; long-running servers that annotate many documents and hold the pool for the process lifetime.

Related errors


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/cb20deb52face8ac. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/pipeline/AnnotatorPool.java:42

  /** A logger for this class */
  private static final Redwood.RedwoodChannels log = Redwood.channels(AnnotatorPool.class);

  /**
   * A cached annotator, including the signature it should cache on.
   */
  private static class CachedAnnotator {
    /** The signature of the annotator. */
    public final String signature;
    /** The cached annotator. */
    public final Lazy<Annotator> annotator;

    /**
     * The straightforward constructor.
     */
    private CachedAnnotator(String signature, Lazy<Annotator> annotator) {
      if (!annotator.isCache()) {
        log.warn("Cached annotator will never GC -- this can cause OOM exceptions!");
      }
      this.signature = signature;
      this.annotator = annotator;
    }

    /** {@inheritDoc} */
    @Override
    public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      CachedAnnotator that = (CachedAnnotator) o;
      return Objects.equals(signature, that.signature) && (Objects.equals(annotator, that.annotator));
    }

    /** {@inheritDoc} */
    @Override
    public int hashCode() {
      int result = signature != null ? signature.hashCode() : 0;

View on GitHub (pinned to 1b7edd19c4)