From ad9b06d03624807c893f184ecde717a9b668ad9c Mon Sep 17 00:00:00 2001 From: fgnm Date: Tue, 30 Apr 2024 17:14:47 +0200 Subject: [PATCH] * Fix many memory leaks (mimetype check, performance panel, render notification) * Try to make libGDX's Pools thread safe --- assets/plugins/plugin-performance-0.1.5.jar | Bin 6125 -> 6056 bytes hyperlap2d-runtime-libgdx | 2 +- .../plugin/performance/PerformancePanel.java | 9 +- .../java/com/badlogic/gdx/utils/Pool.java | 144 ------------------ .../java/com/badlogic/gdx/utils/Pools.java | 74 +++++++++ .../games/rednblack/editor/HyperLap2D.java | 4 +- .../controller/BootstrapInfoCommand.java | 3 + .../editor/proxy/ResourceManager.java | 8 +- .../rednblack/editor/utils/AssetsUtils.java | 35 +++-- .../rednblack/editor/utils/asset/Asset.java | 6 +- .../asset/impl/HyperLap2DLibraryAsset.java | 1 + .../editor/utils/asset/impl/ImageAsset.java | 6 +- .../impl/SpriteAnimationSequenceAsset.java | 6 +- .../editor/view/HyperLap2DScreenMediator.java | 3 +- .../view/ui/followers/PolygonFollower.java | 1 - .../ui/widget/actors/polygon/PolyLine.java | 3 - 16 files changed, 124 insertions(+), 181 deletions(-) delete mode 100644 src/main/java/com/badlogic/gdx/utils/Pool.java create mode 100644 src/main/java/com/badlogic/gdx/utils/Pools.java diff --git a/assets/plugins/plugin-performance-0.1.5.jar b/assets/plugins/plugin-performance-0.1.5.jar index bebc208480fc0659def876ce3ea8f478597d583a..ee3725be6d29b23f5a46dd24ef490d8e8bd4f702 100644 GIT binary patch delta 2710 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 C#3W+? delta 2799 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 diff --git a/hyperlap2d-runtime-libgdx b/hyperlap2d-runtime-libgdx index bd0fc0d4..8457a75a 160000 --- a/hyperlap2d-runtime-libgdx +++ b/hyperlap2d-runtime-libgdx @@ -1 +1 @@ -Subproject commit bd0fc0d4b424470a8eb36ae343509753ebfd8edb +Subproject commit 8457a75aab0f574b2ea9a62bcdd871c71b81671a diff --git a/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanel.java b/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanel.java index b9fb6572..13705d39 100644 --- a/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanel.java +++ b/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanel.java @@ -9,9 +9,6 @@ import com.kotcrab.vis.ui.widget.VisLabel; import com.kotcrab.vis.ui.widget.VisTable; import games.rednblack.h2d.common.UIDraggablePanel; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryUsage; - public class PerformancePanel extends UIDraggablePanel { private final VisTable mainTable; @@ -99,9 +96,9 @@ public class PerformancePanel extends UIDraggablePanel { entitiesCount.setText(entitySubscription.getEntities().size()); fpsLbl.setText(Gdx.graphics.getFramesPerSecond()); - MemoryUsage memoryUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); - long usedMemory = memoryUsage.getUsed() / (1024 * 1024); - long allocatedMemory = memoryUsage.getCommitted() / (1024 * 1024); + long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); + long usedMemory = used / (1024 * 1024); + long allocatedMemory = Runtime.getRuntime().totalMemory() / (1024 * 1024); memoryLabel.getText().clear(); memoryLabel.getText().append(usedMemory); memoryLabel.getText().append(" of "); diff --git a/src/main/java/com/badlogic/gdx/utils/Pool.java b/src/main/java/com/badlogic/gdx/utils/Pool.java deleted file mode 100644 index 84b55bca..00000000 --- a/src/main/java/com/badlogic/gdx/utils/Pool.java +++ /dev/null @@ -1,144 +0,0 @@ -/******************************************************************************* - * Copyright 2011 See AUTHORS file. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ******************************************************************************/ - -package com.badlogic.gdx.utils; - -/** A pool of objects that can be reused to avoid allocation. - * @see Pools - * @author Nathan Sweet */ -abstract public class Pool { - /** The maximum number of objects that will be pooled. */ - public final int max; - /** The highest number of free objects. Can be reset any time. */ - public int peak; - - private final Array freeObjects; - - /** Creates a pool with an initial capacity of 16 and no maximum. */ - public Pool () { - this(16, Integer.MAX_VALUE); - } - - /** Creates a pool with the specified initial capacity and no maximum. */ - public Pool (int initialCapacity) { - this(initialCapacity, Integer.MAX_VALUE); - } - - /** @param initialCapacity The initial size of the array supporting the pool. No objects are created/pre-allocated. Use - * {@link #fill(int)} after instantiation if needed. - * @param max The maximum number of free objects to store in this pool. */ - public Pool (int initialCapacity, int max) { - freeObjects = new Array(false, initialCapacity); - this.max = max; - } - - abstract protected T newObject (); - - /** Returns an object from this pool. The object may be new (from {@link #newObject()}) or reused (previously - * {@link #free(Object) freed}). */ - public T obtain () { - synchronized (freeObjects) { - return freeObjects.size == 0 ? newObject() : freeObjects.pop(); - } - } - - /** Puts the specified object in the pool, making it eligible to be returned by {@link #obtain()}. If the pool already contains - * {@link #max} free objects, the specified object is {@link #discard(Object) discarded}, it is not reset and not added to the - * pool. - *

- * The pool does not check if an object is already freed, so the same object must not be freed multiple times. */ - public void free (T object) { - synchronized (freeObjects) { - if (object == null) throw new IllegalArgumentException("object cannot be null."); - if (freeObjects.size < max) { - freeObjects.add(object); - peak = Math.max(peak, freeObjects.size); - reset(object); - } else - discard(object); - } - } - - /** Adds the specified number of new free objects to the pool. Usually called early on as a pre-allocation mechanism but can be - * used at any time. - * - * @param size the number of objects to be added */ - public void fill (int size) { - synchronized (freeObjects) { - for (int i = 0; i < size; i++) - if (freeObjects.size < max) freeObjects.add(newObject()); - peak = Math.max(peak, freeObjects.size); - } - } - - /** Called when an object is freed to clear the state of the object for possible later reuse. The default implementation calls - * {@link Poolable#reset()} if the object is {@link Poolable}. */ - protected void reset (T object) { - if (object instanceof Poolable) ((Poolable)object).reset(); - } - - /** Called when an object is discarded. This is the case when an object is freed, but the maximum capacity of the pool is - * reached, and when the pool is {@link #clear() cleared} */ - protected void discard (T object) { - reset(object); - } - - /** Puts the specified objects in the pool. Null objects within the array are silently ignored. - *

- * The pool does not check if an object is already freed, so the same object must not be freed multiple times. - * @see #free(Object) */ - public void freeAll (Array objects) { - synchronized (freeObjects) { - if (objects == null) throw new IllegalArgumentException("objects cannot be null."); - Array freeObjects = this.freeObjects; - int max = this.max; - for (int i = 0, n = objects.size; i < n; i++) { - T object = objects.get(i); - if (object == null) continue; - if (freeObjects.size < max) { - freeObjects.add(object); - reset(object); - } else { - discard(object); - } - } - peak = Math.max(peak, freeObjects.size); - } - } - - /** Removes and discards all free objects from this pool. */ - public void clear () { - synchronized (freeObjects) { - Array freeObjects = this.freeObjects; - for (int i = 0, n = freeObjects.size; i < n; i++) - discard(freeObjects.get(i)); - freeObjects.clear(); - } - } - - /** The number of objects available to be obtained. */ - public int getFree () { - synchronized (freeObjects) { - return freeObjects.size; - } - } - - /** Objects implementing this interface will have {@link #reset()} called when passed to {@link Pool#free(Object)}. */ - static public interface Poolable { - /** Resets the object for reuse. Object references should be nulled and fields may be set to default values. */ - public void reset (); - } -} diff --git a/src/main/java/com/badlogic/gdx/utils/Pools.java b/src/main/java/com/badlogic/gdx/utils/Pools.java new file mode 100644 index 00000000..28af8944 --- /dev/null +++ b/src/main/java/com/badlogic/gdx/utils/Pools.java @@ -0,0 +1,74 @@ +package com.badlogic.gdx.utils; + +public class Pools { + static private final ThreadLocal> typePools = new ThreadLocal>() { + protected ObjectMap initialValue () { + return new ObjectMap(); + }; + }; + + /** Returns a new or existing pool for the specified type, stored in a Class to {@link Pool} map. Note the max size is ignored + * if this is not the first time this pool has been requested. */ + static public Pool get (Class type, int max) { + Pool pool = typePools.get().get(type); + if (pool == null) { + pool = new ReflectionPool(type, 4, max); + typePools.get().put(type, pool); + } + return pool; + } + + /** Returns a new or existing pool for the specified type, stored in a Class to {@link Pool} map. The max size of the pool used + * is 100. */ + static public Pool get (Class type) { + return get(type, 100); + } + + /** Sets an existing pool for the specified type, stored in a Class to {@link Pool} map. */ + static public void set (Class type, Pool pool) { + typePools.get().put(type, pool); + } + + /** Obtains an object from the {@link #get(Class) pool}. */ + static public T obtain (Class type) { + return get(type).obtain(); + } + + /** Frees an object from the {@link #get(Class) pool}. */ + static public void free (Object object) { + if (object == null) throw new IllegalArgumentException("object cannot be null."); + Pool pool = typePools.get().get(object.getClass()); + if (pool == null) return; // Ignore freeing an object that was never retained. + pool.free(object); + } + + /** Frees the specified objects from the {@link #get(Class) pool}. Null objects within the array are silently ignored. Objects + * don't need to be from the same pool. */ + static public void freeAll (Array objects) { + freeAll(objects, false); + } + + /** Frees the specified objects from the {@link #get(Class) pool}. Null objects within the array are silently ignored. + * @param samePool If true, objects don't need to be from the same pool but the pool must be looked up for each object. */ + static public void freeAll (Array objects, boolean samePool) { + if (objects == null) throw new IllegalArgumentException("objects cannot be null."); + Pool pool = null; + for (int i = 0, n = objects.size; i < n; i++) { + Object object = objects.get(i); + if (object == null) continue; + if (pool == null) { + pool = typePools.get().get(object.getClass()); + if (pool == null) continue; // Ignore freeing an object that was never retained. + } + pool.free(object); + if (!samePool) pool = null; + } + } + + public static String name() { + return "ThreadSafe Pools"; + } + + private Pools () { + } +} diff --git a/src/main/java/games/rednblack/editor/HyperLap2D.java b/src/main/java/games/rednblack/editor/HyperLap2D.java index a6457128..9bb5a298 100644 --- a/src/main/java/games/rednblack/editor/HyperLap2D.java +++ b/src/main/java/games/rednblack/editor/HyperLap2D.java @@ -91,9 +91,11 @@ public class HyperLap2D implements IProxy, ApplicationListener, Lwjgl3WindowList facade.sendNotification(MsgAPI.RESUME); } + float[] delta = new float[1]; @Override public void render() { - facade.sendNotification(MsgAPI.RENDER, Math.min(Gdx.graphics.getDeltaTime(), 0.1f)); + delta[0] = Math.min(Gdx.graphics.getDeltaTime(), 0.1f); + facade.sendNotification(MsgAPI.RENDER, delta); } @Override diff --git a/src/main/java/games/rednblack/editor/controller/BootstrapInfoCommand.java b/src/main/java/games/rednblack/editor/controller/BootstrapInfoCommand.java index 24fe49e7..bcb308e7 100644 --- a/src/main/java/games/rednblack/editor/controller/BootstrapInfoCommand.java +++ b/src/main/java/games/rednblack/editor/controller/BootstrapInfoCommand.java @@ -2,6 +2,7 @@ package games.rednblack.editor.controller; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.utils.Pools; import games.rednblack.editor.utils.AppConfig; import games.rednblack.h2d.common.HyperLog; import games.rednblack.puremvc.commands.SimpleCommand; @@ -21,5 +22,7 @@ public class BootstrapInfoCommand extends SimpleCommand { HyperLog.info("Shaders version " + gl20.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION)); HyperLog.info("JVM Version: " + System.getProperty("java.version") + " (" + System.getProperty("java.vendor") + ")"); + + HyperLog.info(Pools.name()); } } diff --git a/src/main/java/games/rednblack/editor/proxy/ResourceManager.java b/src/main/java/games/rednblack/editor/proxy/ResourceManager.java index f0057345..7c7dd8a9 100644 --- a/src/main/java/games/rednblack/editor/proxy/ResourceManager.java +++ b/src/main/java/games/rednblack/editor/proxy/ResourceManager.java @@ -91,18 +91,18 @@ public class ResourceManager extends Proxy implements IResourceRetriever { packer.setTransparentColor(Color.WHITE); packer.getTransparentColor().a = 0; - FreeTypeFontGenerator dejaVuSansGenerator = new FreeTypeFontGenerator(Gdx.files.internal("freetypefonts/DejaVuSans.ttf")) { + FreeTypeFontGenerator dejaVuSansGenerator = new FreeTypeFontGenerator(Gdx.files.internal("freetypefonts/DejaVuSans.ttf")) /*{ @Override protected BitmapFont newBitmapFont(BitmapFont.BitmapFontData data, Array pageRegions, boolean integer) { return new ThreadSafeBitmapFont(data, pageRegions, integer); } - }; - FreeTypeFontGenerator monoGenerator = new FreeTypeFontGenerator(Gdx.files.internal("freetypefonts/FiraCode-Regular.ttf")){ + }*/; + FreeTypeFontGenerator monoGenerator = new FreeTypeFontGenerator(Gdx.files.internal("freetypefonts/FiraCode-Regular.ttf"))/*{ @Override protected BitmapFont newBitmapFont(BitmapFont.BitmapFontData data, Array pageRegions, boolean integer) { return new ThreadSafeBitmapFont(data, pageRegions, integer); } - }; + }*/; FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter(); parameter.characters += "⌘⇧⌥\u25CF\u2022"; diff --git a/src/main/java/games/rednblack/editor/utils/AssetsUtils.java b/src/main/java/games/rednblack/editor/utils/AssetsUtils.java index f9a755aa..0b88a5b5 100644 --- a/src/main/java/games/rednblack/editor/utils/AssetsUtils.java +++ b/src/main/java/games/rednblack/editor/utils/AssetsUtils.java @@ -3,6 +3,7 @@ package games.rednblack.editor.utils; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.IntArray; import com.kotcrab.vis.ui.widget.file.FileTypeFilter; import org.apache.commons.io.FileUtils; @@ -10,7 +11,6 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.util.Arrays; public class AssetsUtils { @@ -64,38 +64,45 @@ public class AssetsUtils { return fileTypeFilter; } - public static boolean isAnimationSequence(String[] names) { - if (names.length < 2) return false; - int[] sequenceArray = new int[names.length]; - for (int i = 0; i < names.length; i++) { - String name = names[i]; + public static IntArray sequenceArray = new IntArray(); + + public static boolean isAnimationSequence(Array files) { + if (files.size < 2) return false; + sequenceArray.clear(); + sequenceArray.ensureCapacity(files.size); + sequenceArray.size = files.size; + + for (int i = 0; i < files.size; i++) { + String name = files.get(i); // try to remove extension if any if (name.indexOf(".") > 0) name = name.substring(0, name.indexOf(".")); try { int intValue = Integer.parseInt(name.replaceAll("(.+)_", "")); - sequenceArray[i] = intValue; + sequenceArray.insert(i, intValue); } catch (Exception e) { - sequenceArray[i] = -10; + sequenceArray.insert(i, -1); } } - Arrays.sort(sequenceArray); - if (sequenceArray[0] == 0 && sequenceArray[sequenceArray.length - 1] == sequenceArray.length - 1) { + sequenceArray.sort(); + if (sequenceArray.get(0) == 0 && sequenceArray.get(sequenceArray.size - 1) == sequenceArray.size - 1) { return true; } - return sequenceArray[0] == 1 && sequenceArray[sequenceArray.length - 1] == sequenceArray.length; + return sequenceArray.get(0) == 1 && sequenceArray.get(sequenceArray.size - 1) == sequenceArray.size; } + private final static Array tmpNames = new Array<>(); + public static boolean isAtlasAnimationSequence(Array regions) { if (regions.size < 2) return false; + tmpNames.clear(); //Check old .atlas format - String[] regionNames = new String[regions.size]; for (int i = 0; i < regions.size; i++) { - regionNames[i] = regions.get(i).name; + tmpNames.add(regions.get(i).name); } - if (isAnimationSequence(regionNames)) + if (isAnimationSequence(tmpNames)) return true; //New .atlas format diff --git a/src/main/java/games/rednblack/editor/utils/asset/Asset.java b/src/main/java/games/rednblack/editor/utils/asset/Asset.java index e3c95c95..f7c8e3cf 100644 --- a/src/main/java/games/rednblack/editor/utils/asset/Asset.java +++ b/src/main/java/games/rednblack/editor/utils/asset/Asset.java @@ -60,13 +60,15 @@ public abstract class Asset implements IAsset { // save before importing SceneVO vo = Sandbox.getInstance().sceneVoFromItems(); - projectManager.saveCurrentProject(vo); + if (!skipRepack) //Skip saving if internal resource + projectManager.saveCurrentProject(vo); ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(() -> importAsset(files, progressHandler, skipRepack)); executor.execute(() -> { progressHandler.progressChanged(100); - projectManager.saveCurrentProject(); + if (!skipRepack) //Skip saving if internal resource + projectManager.saveCurrentProject(); try { Thread.sleep(300); } catch (InterruptedException e) { diff --git a/src/main/java/games/rednblack/editor/utils/asset/impl/HyperLap2DLibraryAsset.java b/src/main/java/games/rednblack/editor/utils/asset/impl/HyperLap2DLibraryAsset.java index 9a198060..02f075bb 100644 --- a/src/main/java/games/rednblack/editor/utils/asset/impl/HyperLap2DLibraryAsset.java +++ b/src/main/java/games/rednblack/editor/utils/asset/impl/HyperLap2DLibraryAsset.java @@ -134,6 +134,7 @@ public class HyperLap2DLibraryAsset extends Asset { ResolutionManager resolutionManager = Facade.getInstance().retrieveProxy(ResolutionManager.NAME); resolutionManager.rePackProjectImagesForAllResolutionsSync(); + projectManager.saveCurrentProject(); progressHandler.progressChanged(100); diff --git a/src/main/java/games/rednblack/editor/utils/asset/impl/ImageAsset.java b/src/main/java/games/rednblack/editor/utils/asset/impl/ImageAsset.java index 5c1df741..b1d48b79 100644 --- a/src/main/java/games/rednblack/editor/utils/asset/impl/ImageAsset.java +++ b/src/main/java/games/rednblack/editor/utils/asset/impl/ImageAsset.java @@ -26,11 +26,13 @@ import java.util.function.Consumer; public class ImageAsset extends Asset { + private final Array names = new Array<>(); + @Override public int matchType(Array files) { - String[] names = new String[files.size]; + names.clear(); for (int i = 0; i < files.size; i++) { - names[i] = files.get(i).nameWithoutExtension(); + names.add(files.get(i).nameWithoutExtension()); } return AssetsUtils.isAnimationSequence(names) ? AssetsUtils.TYPE_UNKNOWN : super.matchType(files); diff --git a/src/main/java/games/rednblack/editor/utils/asset/impl/SpriteAnimationSequenceAsset.java b/src/main/java/games/rednblack/editor/utils/asset/impl/SpriteAnimationSequenceAsset.java index b671badc..67b96031 100644 --- a/src/main/java/games/rednblack/editor/utils/asset/impl/SpriteAnimationSequenceAsset.java +++ b/src/main/java/games/rednblack/editor/utils/asset/impl/SpriteAnimationSequenceAsset.java @@ -15,11 +15,13 @@ import java.util.Objects; public class SpriteAnimationSequenceAsset extends SpriteAnimationAtlasAsset { + private final Array names = new Array<>(); + @Override public int matchType(Array files) { - String[] names = new String[files.size]; + names.clear(); for (int i = 0; i < files.size; i++) { - names[i] = files.get(i).nameWithoutExtension(); + names.add(files.get(i).nameWithoutExtension()); } return AssetsUtils.isAnimationSequence(names) ? getType() : AssetsUtils.TYPE_UNKNOWN; } diff --git a/src/main/java/games/rednblack/editor/view/HyperLap2DScreenMediator.java b/src/main/java/games/rednblack/editor/view/HyperLap2DScreenMediator.java index ae2b01d7..66874d8b 100644 --- a/src/main/java/games/rednblack/editor/view/HyperLap2DScreenMediator.java +++ b/src/main/java/games/rednblack/editor/view/HyperLap2DScreenMediator.java @@ -80,7 +80,8 @@ public class HyperLap2DScreenMediator extends Mediator { viewComponent.resume(); break; case MsgAPI.RENDER: - viewComponent.render(notification.getBody()); + float[] delta = notification.getBody(); + viewComponent.render(delta[0]); break; case MsgAPI.RESIZE: int[] data = notification.getBody(); diff --git a/src/main/java/games/rednblack/editor/view/ui/followers/PolygonFollower.java b/src/main/java/games/rednblack/editor/view/ui/followers/PolygonFollower.java index e0480f06..e4d875e2 100644 --- a/src/main/java/games/rednblack/editor/view/ui/followers/PolygonFollower.java +++ b/src/main/java/games/rednblack/editor/view/ui/followers/PolygonFollower.java @@ -1,7 +1,6 @@ package games.rednblack.editor.view.ui.followers; import com.artemis.ComponentMapper; -import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.OrthographicCamera; diff --git a/src/main/java/games/rednblack/editor/view/ui/widget/actors/polygon/PolyLine.java b/src/main/java/games/rednblack/editor/view/ui/widget/actors/polygon/PolyLine.java index 5d6fe3e4..235e3bf1 100644 --- a/src/main/java/games/rednblack/editor/view/ui/widget/actors/polygon/PolyLine.java +++ b/src/main/java/games/rednblack/editor/view/ui/widget/actors/polygon/PolyLine.java @@ -1,12 +1,9 @@ package games.rednblack.editor.view.ui.widget.actors.polygon; import com.badlogic.gdx.graphics.g2d.Batch; -import com.badlogic.gdx.math.Intersector; -import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Touchable; -import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Pool; import space.earlygrey.shapedrawer.ShapeDrawer;