mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
34d189ae09
Summary: Changelog: [internal] Introducing LeakChecker. A tool that checks if all native components have been cleaned up when surface is stopped. **Known shortcomings**: - LeakChecker is only enabled in debug builds and the existence of leaks is logged to console. - For now, Leak Checker looks at N-1 screen. This is intentional as there is a known limitation of React that doesn't free up all shadow nodes when surface is stopped. Because of this, the use of LeakChecker is not intuitive and I'll work with React team to try to work around this. - It doesn't help locating the leak, it only informs that leak is present. I'll be looking into ways to help locate the leak. Reviewed By: JoshuaGross, mdvacca Differential Revision: D26727461 fbshipit-source-id: 8350190b99f24642f8e15a3c2e1d79cfaa810d3d
64 lines
2.0 KiB
C++
64 lines
2.0 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include "LeakChecker.h"
|
|
|
|
#include <glog/logging.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
LeakChecker::LeakChecker(
|
|
RuntimeExecutor const &runtimeExecutor,
|
|
GarbageCollectionTrigger const &garbageCollectionTrigger)
|
|
: runtimeExecutor_(runtimeExecutor),
|
|
garbageCollectionTrigger_(garbageCollectionTrigger) {}
|
|
|
|
void LeakChecker::uiManagerDidCreateShadowNodeFamily(
|
|
ShadowNodeFamily::Shared const &shadowNodeFamily) const {
|
|
registry_.add(shadowNodeFamily);
|
|
}
|
|
|
|
void LeakChecker::stopSurface(SurfaceId surfaceId) {
|
|
garbageCollectionTrigger_();
|
|
|
|
if (previouslyStoppedSurface_ > 0) {
|
|
// Dispatch the check onto JavaScript thread to make sure all other
|
|
// cleanup code has had chance to run.
|
|
runtimeExecutor_([previouslySoppedSurface = previouslyStoppedSurface_,
|
|
this](jsi::Runtime &) {
|
|
// For now check the previous surface because React uses double
|
|
// buffering which keeps the surface that was just stopped in
|
|
// memory. This is a documented problem in the last point of
|
|
// https://github.com/facebook/react/issues/16087
|
|
checkSurfaceForLeaks(previouslySoppedSurface);
|
|
});
|
|
}
|
|
|
|
previouslyStoppedSurface_ = surfaceId;
|
|
}
|
|
|
|
void LeakChecker::checkSurfaceForLeaks(SurfaceId surfaceId) const {
|
|
auto weakFamilies = registry_.weakFamiliesForSurfaceId(surfaceId);
|
|
uint numberOfLeaks = 0;
|
|
for (auto const &weakFamily : weakFamilies) {
|
|
auto strong = weakFamily.lock();
|
|
if (strong) {
|
|
++numberOfLeaks;
|
|
}
|
|
}
|
|
if (numberOfLeaks > 0) {
|
|
LOG(ERROR) << "[LeakChecker] Surface with id: " << surfaceId
|
|
<< " has leaked " << numberOfLeaks << " components out of "
|
|
<< weakFamilies.size();
|
|
}
|
|
registry_.removeFamiliesWithSurfaceId(surfaceId);
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|