Recycle CSSNodes
Summary: Adds a pool to recycle CSSNodes within UIManager. A follow-up diff will hook this up to a memory pressure listener to drop the pool on memory pressure. Reviewed By: emilsjolander Differential Revision: D4189532 fbshipit-source-id: 46583546f71a8c59853e1dd124de31657b3c617b
This commit is contained in:
parent
7c91f894ba
commit
bd8745b1fd
|
@ -7,14 +7,15 @@ SUB_PROJECTS = [
|
|||
android_library(
|
||||
name = 'common',
|
||||
srcs = glob(['**/*.java'], excludes=SUB_PROJECTS),
|
||||
deps = [
|
||||
':build_config',
|
||||
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
],
|
||||
exported_deps = [
|
||||
react_native_dep('java/com/facebook/proguard/annotations:annotations'),
|
||||
],
|
||||
deps = [
|
||||
':build_config',
|
||||
react_native_dep('third-party/android/support/v4:lib-support-v4'),
|
||||
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.react.common;
|
||||
|
||||
import android.support.v4.util.Pools;
|
||||
|
||||
/**
|
||||
* Like {@link android.support.v4.util.Pools.SynchronizedPool} with the option to clear the pool
|
||||
* (e.g. on memory pressure).
|
||||
*/
|
||||
public class ClearableSynchronizedPool<T> implements Pools.Pool<T> {
|
||||
|
||||
private final Object[] mPool;
|
||||
private int mSize = 0;
|
||||
|
||||
public ClearableSynchronizedPool(int maxSize) {
|
||||
mPool = new Object[maxSize];
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T acquire() {
|
||||
if (mSize == 0) {
|
||||
return null;
|
||||
}
|
||||
mSize--;
|
||||
final int lastIndex = mSize;
|
||||
T toReturn = (T) mPool[lastIndex];
|
||||
mPool[lastIndex] = null;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean release(T obj) {
|
||||
if (mSize == mPool.length) {
|
||||
return false;
|
||||
}
|
||||
mPool[mSize] = obj;
|
||||
mSize++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
mPool[i] = null;
|
||||
}
|
||||
mSize = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import com.facebook.csslayout.CSSNode;
|
||||
import com.facebook.react.common.ClearableSynchronizedPool;
|
||||
|
||||
/**
|
||||
* Static holder for a recycling pool of CSSNodes.
|
||||
*/
|
||||
public class CSSNodePool {
|
||||
|
||||
private static final Object sInitLock = new Object();
|
||||
private static ClearableSynchronizedPool<CSSNode> sPool;
|
||||
|
||||
public static ClearableSynchronizedPool<CSSNode> get() {
|
||||
if (sPool != null) {
|
||||
return sPool;
|
||||
}
|
||||
|
||||
synchronized (sInitLock) {
|
||||
if (sPool == null) {
|
||||
sPool = new ClearableSynchronizedPool<CSSNode>(1024);
|
||||
}
|
||||
return sPool;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,7 +74,15 @@ public class ReactShadowNode {
|
|||
private float mAbsoluteBottom;
|
||||
private final Spacing mDefaultPadding = new Spacing(0);
|
||||
private final Spacing mPadding = new Spacing(CSSConstants.UNDEFINED);
|
||||
private final CSSNode mCSSNode = new CSSNode();
|
||||
private final CSSNode mCSSNode;
|
||||
|
||||
public ReactShadowNode() {
|
||||
CSSNode node = CSSNodePool.get().acquire();
|
||||
if (node == null) {
|
||||
node = new CSSNode();
|
||||
}
|
||||
mCSSNode = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nodes that return {@code true} will be treated as "virtual" nodes. That is, nodes that are not
|
||||
|
@ -190,7 +198,7 @@ public class ReactShadowNode {
|
|||
return mChildren == null ? -1 : mChildren.indexOf(child);
|
||||
}
|
||||
|
||||
public void removeAllChildren() {
|
||||
public void removeAndDisposeAllChildren() {
|
||||
if (getChildCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -202,6 +210,8 @@ public class ReactShadowNode {
|
|||
}
|
||||
ReactShadowNode toRemove = getChildAt(i);
|
||||
toRemove.mParent = null;
|
||||
toRemove.dispose();
|
||||
|
||||
decrease += toRemove.mIsLayoutOnly ? toRemove.mTotalNativeChildren : 1;
|
||||
}
|
||||
Assertions.assertNotNull(mChildren).clear();
|
||||
|
@ -654,4 +664,9 @@ public class ReactShadowNode {
|
|||
public String toString() {
|
||||
return mCSSNode.toString();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
mCSSNode.reset();
|
||||
CSSNodePool.get().release(mCSSNode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -652,12 +652,17 @@ public class UIImplementation {
|
|||
}
|
||||
|
||||
protected final void removeShadowNode(ReactShadowNode nodeToRemove) {
|
||||
mNativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove);
|
||||
removeShadowNodeRecursive(nodeToRemove);
|
||||
nodeToRemove.dispose();
|
||||
}
|
||||
|
||||
private void removeShadowNodeRecursive(ReactShadowNode nodeToRemove) {
|
||||
NativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove);
|
||||
mShadowNodeRegistry.removeNode(nodeToRemove.getReactTag());
|
||||
for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
|
||||
removeShadowNode(nodeToRemove.getChildAt(i));
|
||||
removeShadowNodeRecursive(nodeToRemove.getChildAt(i));
|
||||
}
|
||||
nodeToRemove.removeAllChildren();
|
||||
nodeToRemove.removeAndDisposeAllChildren();
|
||||
}
|
||||
|
||||
private void measureLayout(int tag, int ancestorTag, int[] outputBuffer) {
|
||||
|
|
Loading…
Reference in New Issue