Enrollment 28.2.0
Loading...
Searching...
No Matches
Java

User is able to use Java classes generated by SWIG tool, using Java version 8.

Memory Management

The Java Garbage Collector (GC) manages memory in the JVM heap, ensuring efficient allocation and deallocation of resources within that space.

In the case of the enrollment-sdk, objects in the Java heap are generally small. However, these objects often create significantly larger amounts of unmanaged (native) memory, which contributes to the overall process memory usage.

Since the Java heap objects are small, the GC may not be triggered frequently, potentially leading to high process memory consumption due to unmanaged memory growth.

The following sections outline how lifetime works and which levers you can combine for your use case.

One generated type: GC by default, eager release when needed

All Java proxy classes generated for the enrollment-sdk are a single surface type per C++ type. They implement java.lang.AutoCloseable so you may use try-with-resources or call close() (which forwards to SWIG delete()) when you need deterministic release of native memory (for example under memory pressure or in tight loops creating many proxies).

In typical applications it is enough to rely on the garbage collector: when a proxy becomes unreachable, SWIG’s finalization path can reclaim the native side as well. You are not required to wrap every object in try-with-resources; use eager release only where profiling shows native memory growth or latency requires it.

AutoCloseable exists so both styles are supported without a second wrapper type.

Use small heap

If your Java application uses only small objects, consider setting the maximum heap size as low as possible using the -Xmx option during application startup.

This will cause the GC to run more frequently, ensuring that unmanaged memory is released more effectively.

Use try-with-resources when you need eager cleanup

When you choose deterministic cleanup, use the try-with-resources statement so close() is invoked automatically. This is especially useful where many short-lived proxies are created and you want native memory freed promptly.

CodeCode with try-with-resources
// Please note that the sample source code
// provided here is for informational purposes
// only and should not be used for production
// purposes without proper testing and modification.
private static Face getFace(byte[] img) {
Bytes bytes = new Bytes(img);
Image image = Image.Decode(bytes);
FaceCapture capture = new FaceCapture(image);
FaceDetector.Config cfg = new FaceDetector.Config();
FaceDetector detector = new FaceDetector(cfg);
Faces faces = capture.DetectWith(detector);
if (faces.isEmpty()) {
return null;
}
return faces.get(0);
}
// Please note that the sample source code
// provided here is for informational purposes
// only and should not be used for production
// purposes without proper testing and modification.
private static Face getFace(byte[] img) {
try (Bytes bytes = new Bytes(img); Image image = Image.Decode(bytes);
FaceCapture capture = new FaceCapture(image);
FaceDetector.Config cfg = new FaceDetector.Config();
FaceDetector detector = new FaceDetector(cfg);
Faces faces = capture.DetectWith(detector)) {
if (faces.isEmpty()) {
return null;
}
return faces.get(0);
}
}

Use close() with caution

You can call close() to free the native memory immediately (same effect as successful completion of a try-with-resources block). Do not use the Java object after it has been closed. If any method is called on a closed Java object, a RuntimeException or NullPointerException is thrown.

IDE “resource leak” warnings and GC-only code

Eclipse JDT and editors based on it (including VS Code / Cursor with the Java language server) often warn when a local variable holds an AutoCloseable value and neither try-with-resources nor close() appears on all paths. That does not mean GC-only usage is wrong for this SDK: it is a static analysis limitation.

If you intentionally rely on GC for a scope, you can, for example:

  • Narrow a try-with-resources block around the few objects that need eager release, or
  • Add @SuppressWarnings("resource") on the enclosing method (or, where your Java level allows, on the variable) for that intentional GC lifetime, or
  • Adjust your project’s Java compiler “resource / closeable” diagnostics if your team policy allows.

Force GC

While Java GC is automatic, you can request garbage collection using System.gc(). This should be used cautiously, as it is a suggestion, not a guarantee.

For applications with high unmanaged memory usage, consider monitoring total memory and triggering the garbage collector if needed:

// Please note that the sample source code provided here is for informational purposes
// only and should not be used for production purposes without proper testing and
// modification.
private static void triggerGarbageCollector() {
// Set process memory limit to 2GB
long maxMemoryLimit = 2L * 1024 * 1024 * 1024;
Runtime runtime = Runtime.getRuntime();
while (!Thread.currentThread().isInterrupted()) {
long totalMemory = runtime.totalMemory() - runtime.freeMemory();
if (totalMemory > maxMemoryLimit) {
// Request garbage collection
System.gc();
}
// Check every second
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}

Use it in the main function of your application:

Thread memoryLimiter = new Thread(() -> triggerGarbageCollector());
memoryLimiter.start();

Exception Propagation

Exception from Java implementation of Interface Exception in Enrollment SDK native code Exception propagated back to Java
EnrollmentException and its subclasses EnrollmentException and its subclasses EnrollmentException and its subclasses
IllegalArgumentException std::invalid_argument IllegalArgumentException
IndexOutOfBoundsException std::out_of_range IndexOutOfBoundsException
RuntimeException std::runtime_exception RuntimeException
Exception std::runtime_exception RuntimeException

Initialization

Because Java requires native libraries to be loaded before any SDK function can be called, LoadNativeLibrary() must be the first SDK function invoked.

After the native library has been loaded, you can either rely on the SDK's auto-init functionality or initialize the SDK manually.

For convenience, the SDK also provides an overload:

LoadNativeLibrary(() -> InitializerConfig)
SDK initialisation configuration for manual init.
Definition InitializerConfig.h:50

This function first calls LoadNativeLibrary(), then invokes the supplied lambda, and finally passes the lambda's return value to Initialize(InitializerConfig).