|
Enrollment 28.2.0
|
User is able to use Java classes generated by SWIG tool, using Java version 8.
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.
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.
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.
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.
| Code | Code 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) {
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);
}
}
|
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.
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:
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:
Use it in the main function of your application:
| 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 |
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:
This function first calls LoadNativeLibrary(), then invokes the supplied lambda, and finally passes the lambda's return value to Initialize(InitializerConfig).