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
This commit is contained in:
David Aurelio
2019-07-19 17:16:46 -07:00
committed by Facebook Github Bot
parent 4e4ef06de1
commit 8c0eed3c75
6 changed files with 88 additions and 29 deletions

View File

@@ -50,6 +50,7 @@ yoga_java_library(
visibility = ["PUBLIC"],
deps = [
":jni",
FBJNI_JAVA_TARGET,
INFER_ANNOTATIONS_TARGET,
JSR_305_TARGET,
PROGRUARD_ANNOTATIONS_TARGET,

View File

@@ -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();

View File

@@ -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<YogaNodeJNIBase> 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;

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
};
}
}

View File

@@ -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,
],
)