Native Memory Not Released After Watermarker.close() — Confirmed via RSS vs NMT Delta Analysis

Hello GroupDocs Support Team,

We are using GroupDocs.Watermark for Java in our Spring Boot application running on Kubernetes (Java 8, OpenJDK, -Xmx5120m). We have observed that native memory is not being released after Watermarker.close() is called, and we would like to confirm whether this is a known issue or expected behavior.

Environment

  • GroupDocs.Watermark for Java
  • Java 8 (OpenJDK, java-8-openjdk-amd64)
  • Spring Boot, Kubernetes Pod
  • JVM flags: -Xmx5120m -Xms5120m -XX:+UseParallelGC -XX:NativeMemoryTracking=summary

What We Observed

We measured RSS (Resident Set Size) before and after processing watermark requests using /proc/1/status:

Before watermark (2 PDF files): VmRSS: 3,356,916 kB
After watermark  (2 PDF files): VmRSS: 3,580,956 kB
Increase                       :         +224,040 kB (+219MB)
After 11 minutes (no activity) : VmRSS: 3,580,932 kB  (unchanged)

The two files processed were 5.9MB and 2.7MB respectively.

What We Verified

To determine whether this was a JVM heap issue or native memory issue, we compared JVM Native Memory Tracking (NMT) before and after:

NMT Total committed — Before: 5,811MB
NMT Total committed — After : 5,812MB
NMT increase                :    +1MB
RSS increase                : +219MB

All NMT categories (Java Heap, Class, Thread, Code, GC, Internal) showed virtually no change, while RSS increased by 219MB. This strongly suggests that GroupDocs.Watermark is allocating memory directly via OS-level native calls, outside of JVM-tracked memory.

We also performed the following additional verifications:

  1. Watermarker is properly closed via try-with-resources — close() is guaranteed to be called
  2. Forced GC via jcmd 1 GC.run — RSS did not decrease after GC
  3. Waited 11 minutes after processing — RSS remained unchanged
  4. Old Gen heap usage was only 6.43% at the time — GC trigger conditions were far from met, ruling out GC timing as the cause

Our Questions

  1. Is it expected behavior that GroupDocs.Watermark allocates native memory outside the JVM heap?
  2. Is native memory expected to be released upon close() / dispose()? If so, why is RSS not decreasing in our tests?
  3. Is there a known workaround or configuration option to ensure native memory is returned to the OS after processing?
  4. Is this a known issue in the current version, and if so, is there a fix planned?

We are experiencing repeated OOM Kill events in our Kubernetes Pod (limit: 10Gi) due to this memory accumulation, and resolving this is critical for stable operation.

Thank you for your time and support. We look forward to your response.