I use JmeConver in my model-converter GUI app to convert my gltf models to j3o format and generate model icons.
After converting a bunch of models I am getting OutOfMemoryError. After looking deeper into memory usage I noticed the allocated direct memory is never getting freed. Looking deeper into the code I noticed it creates a new DesktopAssetManager every time I am calling convert.setSourceRoot() and for some reason, the allocated buffers from the old asset managers are never released.
After I modified the code to reuse the same AssetReader and just reset the root path instead of creating a new AssetReader then the issue is resolved and I see memory is properly freed.
this is my modified AssetReader class just in case:
(added setAssetRoot() and removeAssetRoot())
public class AssetReader {
public static final String DESKTOP_ASSET_CONFIG = "/com/jme3/asset/Desktop.cfg";
static Logger log = LoggerFactory.getLogger(AssetReader.class);
private Path root;
private final AssetManager assets;
public AssetReader( ) {
this((URL) null);
}
public AssetReader(URL assetConfig ) {
if( assetConfig == null ) {
assetConfig = getClass().getResource(DESKTOP_ASSET_CONFIG);
log.info("Found assetConfig:" + assetConfig);
}
this.assets = new DesktopAssetManager(assetConfig);
}
public AssetReader(AssetManager assets) {
this.assets = assets;
}
public void setAssetRoot(File assetRoot) {
if (root != null) {
assets.unregisterLocator(root.toString(), FileLocator.class);
}
try {
this.root = assetRoot.getCanonicalFile().toPath();
} catch( java.io.IOException e ) {
throw new RuntimeException("Error getting canonical path for:" + assetRoot, e);
}
log.info("Using source asset root:" + root);
assets.registerLocator(root.toString(), FileLocator.class);
}
public void removeAssetRoot() {
if (root != null) {
assets.unregisterLocator(root.toString(), FileLocator.class);
root = null;
}
}
public AssetManager getAssetManager() {
return assets;
}
public Spatial loadModel( File f ) {
if (root == null) {
throw new RuntimeException("Asset root is not set.");
}
log.debug("loadModel(" + f + ")");
if( !f.exists() ) {
throw new IllegalArgumentException("Model file does not exist:" + f);
}
try {
// Make sure the file is completely collapsed into canonical form.
// Note: apparently getAbsoluteFile() is not good enough.
f = f.getCanonicalFile();
} catch( IOException e ) {
throw new IllegalArgumentException("File cannot be converted to canonical path:" + f, e);
}
// Find the relative path
String path = root.relativize(f.getAbsoluteFile().toPath()).toString();
log.info("Loading asset:" + path);
// Make sure the cache is clear
assets.clearCache();
// AssetManager doesn't really give us a better way to resolve types
// so we'll make some assumptions... it helps that we control the
// asset manager ourselves here.
String extension = Files.getFileExtension(f.getName());
if( "gltf".equalsIgnoreCase(extension) || "glb".equalsIgnoreCase(extension) ) {
// We do special setup for GLTF
return assets.loadModel(GltfExtrasLoader.createModelKey(path));
} else {
return assets.loadModel(path);
}
}
}
Any chance we have this change added to the main repo?