From 8c0eed3c755d4cd4e9ae11aa78c6768e7aa396be Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Fri, 19 Jul 2019 17:16:46 -0700 Subject: [PATCH] Add PhantomRef based YogaNode subclass Summary: Adds a subclass of `YogaNodeJNIBase` that uses `PhantomReference` for deallocating native memory rather than `Object#finalize()`. This should help making garbage collection more efficient. Reviewed By: amir-shalem Differential Revision: D16182667 fbshipit-source-id: d310fdb6af184168c43462b24f5e18ab5d0d7ad0 --- java/BUCK | 1 + java/com/facebook/yoga/YogaNode.java | 4 +- java/com/facebook/yoga/YogaNodeJNIBase.java | 34 ++++----------- .../facebook/yoga/YogaNodeJNIFinalizer.java | 34 +++++++++++++++ .../facebook/yoga/YogaNodeJNIPhantomRefs.java | 41 +++++++++++++++++++ lib/fb/BUCK | 3 +- 6 files changed, 88 insertions(+), 29 deletions(-) create mode 100644 java/com/facebook/yoga/YogaNodeJNIFinalizer.java create mode 100644 java/com/facebook/yoga/YogaNodeJNIPhantomRefs.java diff --git a/java/BUCK b/java/BUCK index 18bc6f8e..e25d42fd 100644 --- a/java/BUCK +++ b/java/BUCK @@ -50,6 +50,7 @@ yoga_java_library( visibility = ["PUBLIC"], deps = [ ":jni", + FBJNI_JAVA_TARGET, INFER_ANNOTATIONS_TARGET, JSR_305_TARGET, PROGRUARD_ANNOTATIONS_TARGET, diff --git a/java/com/facebook/yoga/YogaNode.java b/java/com/facebook/yoga/YogaNode.java index 1c75d1d6..9abb1412 100644 --- a/java/com/facebook/yoga/YogaNode.java +++ b/java/com/facebook/yoga/YogaNode.java @@ -10,11 +10,11 @@ import javax.annotation.Nullable; public abstract class YogaNode { public static YogaNode create() { - return new YogaNodeJNIBase(); + return new YogaNodeJNIFinalizer(); } public static YogaNode create(YogaConfig config) { - return new YogaNodeJNIBase(config); + return new YogaNodeJNIFinalizer(config); } public abstract void reset(); diff --git a/java/com/facebook/yoga/YogaNodeJNIBase.java b/java/com/facebook/yoga/YogaNodeJNIBase.java index 3fc4c0ad..a2f7845e 100644 --- a/java/com/facebook/yoga/YogaNodeJNIBase.java +++ b/java/com/facebook/yoga/YogaNodeJNIBase.java @@ -12,7 +12,7 @@ import java.util.List; import javax.annotation.Nullable; @DoNotStrip -public class YogaNodeJNIBase extends YogaNode implements Cloneable { +public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { /* Those flags needs be in sync with YGJNI.cpp */ private static final byte MARGIN = 1; @@ -35,7 +35,7 @@ public class YogaNodeJNIBase extends YogaNode implements Cloneable { @Nullable private List mChildren; @Nullable private YogaMeasureFunction mMeasureFunction; @Nullable private YogaBaselineFunction mBaselineFunction; - private long mNativePointer; + protected long mNativePointer; @Nullable private Object mData; @DoNotStrip @@ -46,37 +46,21 @@ public class YogaNodeJNIBase extends YogaNode implements Cloneable { private boolean mHasNewLayout = true; - public YogaNodeJNIBase() { - mNativePointer = YogaNative.jni_YGNodeNew(); - if (mNativePointer == 0) { + private YogaNodeJNIBase(long nativePointer) { + if (nativePointer == 0) { throw new IllegalStateException("Failed to allocate native memory"); } + mNativePointer = nativePointer; } - public YogaNodeJNIBase(YogaConfig config) { - mNativePointer = YogaNative.jni_YGNodeNewWithConfig(config.mNativePointer); - if (mNativePointer == 0) { - throw new IllegalStateException("Failed to allocate native memory"); - } + YogaNodeJNIBase() { + this(YogaNative.jni_YGNodeNew()); } - @Override - protected void finalize() throws Throwable { - try { - freeNatives(); - } finally { - super.finalize(); - } + YogaNodeJNIBase(YogaConfig config) { + this(YogaNative.jni_YGNodeNewWithConfig(config.mNativePointer)); } - /* frees the native underlying YGNode. Useful for testing. */ - public void freeNatives() { - if (mNativePointer > 0) { - long nativePointer = mNativePointer; - mNativePointer = 0; - YogaNative.jni_YGNodeFree(nativePointer); - } - } public void reset() { mMeasureFunction = null; mBaselineFunction = null; diff --git a/java/com/facebook/yoga/YogaNodeJNIFinalizer.java b/java/com/facebook/yoga/YogaNodeJNIFinalizer.java new file mode 100644 index 00000000..cee7b0e8 --- /dev/null +++ b/java/com/facebook/yoga/YogaNodeJNIFinalizer.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + */ +package com.facebook.yoga; + +public class YogaNodeJNIFinalizer extends YogaNodeJNIBase { + public YogaNodeJNIFinalizer() { + super(); + } + + public YogaNodeJNIFinalizer(YogaConfig config) { + super(config); + } + + @Override + protected void finalize() throws Throwable { + try { + freeNatives(); + } finally { + super.finalize(); + } + } + + public void freeNatives() { + if (mNativePointer != 0) { + long nativePointer = mNativePointer; + mNativePointer = 0; + YogaNative.jni_YGNodeFree(nativePointer); + } + } +} diff --git a/java/com/facebook/yoga/YogaNodeJNIPhantomRefs.java b/java/com/facebook/yoga/YogaNodeJNIPhantomRefs.java new file mode 100644 index 00000000..a87defd8 --- /dev/null +++ b/java/com/facebook/yoga/YogaNodeJNIPhantomRefs.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + */ +package com.facebook.yoga; + +import com.facebook.jni.DestructorThread; + +public class YogaNodeJNIPhantomRefs extends YogaNodeJNIBase { + public YogaNodeJNIPhantomRefs() { + super(); + registerPhantomRef(this, mNativePointer); + } + + public YogaNodeJNIPhantomRefs(YogaConfig config) { + super(config); + registerPhantomRef(this, mNativePointer); + } + + @Override + public YogaNodeJNIPhantomRefs cloneWithoutChildren() { + YogaNodeJNIPhantomRefs clone = (YogaNodeJNIPhantomRefs) super.cloneWithoutChildren(); + registerPhantomRef(clone, clone.mNativePointer); + return clone; + } + + private static final void registerPhantomRef(YogaNode node, final long nativePointer) { + new DestructorThread.Destructor(node) { + private long mNativePointer = nativePointer; + @Override + protected void destruct() { + if (mNativePointer != 0) { + YogaNative.jni_YGNodeFree(mNativePointer); + mNativePointer = 0; + } + } + }; + } +} diff --git a/lib/fb/BUCK b/lib/fb/BUCK index d078c1b6..df65844d 100644 --- a/lib/fb/BUCK +++ b/lib/fb/BUCK @@ -2,7 +2,7 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "FBJNI_JAVA_TARGET", "JNI_TARGET", "YOGA_ROOTS", "subdir_glob", "yoga_cxx_library", "yoga_prebuilt_cxx_library") +load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "JNI_TARGET", "YOGA_ROOTS", "subdir_glob", "yoga_cxx_library", "yoga_prebuilt_cxx_library") yoga_prebuilt_cxx_library( name = "ndklog", @@ -40,7 +40,6 @@ yoga_cxx_library( visibility = ["PUBLIC"], deps = [ ":ndklog", - FBJNI_JAVA_TARGET, JNI_TARGET, ], )