Skip to content

Commit

Permalink
[camerax] Shorten interval for releasing weak references to Dart-wrap…
Browse files Browse the repository at this point in the history
…ped native objects (flutter#6493)

This PR:

1. Shortens the `InstanceManager`'s default time interval that it waits to remove references to Dart-wrapped Android native objects. The shortened interval matches `webview_flutter_android`s `InstanceManager`; because it has been tested by that plugin, we expect it not to impact performance and this could help reduce overall memory usage by the plugin.
2. Dynamically shortens that same time interval whenever image streaming is started/stopped to account for the increased memory usage that this camera use case requires.

Fixes flutter/flutter#145893.
  • Loading branch information
camsim99 authored Apr 10, 2024
1 parent d680544 commit 6f0ed15
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 7 deletions.
8 changes: 8 additions & 0 deletions packages/camera/camera_android_camerax/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 0.6.3

* Shortens default interval that internal Java `InstanceManager` uses to release garbage collected weak references to
native objects.
* Dynamically shortens interval that internal Java `InstanceManager` uses to release garbage collected weak references to
native objects when an `ImageAnalysis.Analyzer` is set/removed to account for increased memory usage of analyzing
images that may cause a crash.

## 0.6.2

* Adds support to control video FPS and bitrate. See `CameraController.withSettings`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ public void setAnalyzer(@NonNull Long identifier, @NonNull Long analyzerIdentifi
throw new IllegalStateException("Context must be set to set an Analyzer.");
}

// Shorten time interval used to define how often the instanceManager removes garbage
// collected weak references to native Android objects that it manages in order to
// account for the increased memory usage that comes from analyzing images with an
// ImageAnalysis.Analyzer.
instanceManager.setClearFinalizedWeakReferencesInterval(
InstanceManager.CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL_FOR_IMAGE_ANALYSIS);
instanceManager.releaseAllFinalizedInstances();

getImageAnalysisInstance(identifier)
.setAnalyzer(
ContextCompat.getMainExecutor(context),
Expand All @@ -81,6 +89,13 @@ public void clearAnalyzer(@NonNull Long identifier) {
ImageAnalysis imageAnalysis =
(ImageAnalysis) Objects.requireNonNull(instanceManager.getInstance(identifier));
imageAnalysis.clearAnalyzer();

// Restore the default time interval used to define how often the instanceManager
// removes garbage collected weak references to native Android objects that it
// manages since analyzing images with an ImageAnalysis.Analyzer, which involves
// increased memory usage, is finished.
instanceManager.setClearFinalizedWeakReferencesInterval(
InstanceManager.DEFAULT_CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL);
}

/** Dynamically sets the target rotation of the {@link ImageAnalysis}. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,25 @@ public class InstanceManager {
// Host uses identifiers >= 2^16 and Dart is expected to use values n where,
// 0 <= n < 2^16.
private static final long MIN_HOST_CREATED_IDENTIFIER = 65536;
private static final long CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL = 30000;
private static final String TAG = "InstanceManager";

/**
* The default time interval used to define how often this instance removes garbage collected weak
* references to native Android objects that this instance manages.
*/
public static final long DEFAULT_CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL = 3000;

/**
* The time interval used to define how often this instance removes garbage collected weak
* references to native Android objects that this instance manages, specifically when an {@code
* ImageAnalysis.Analyzer} is set on an {@code ImageAnalysis} instance to support image streaming.
*
* <p>Streaming images with an {@code ImageAnalysis.Analyzer} involves increased memory usage, so
* this interval, which is lower than the default {@link
* DEFAULT_CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL} interval, accommodates this fact.
*/
public static final long CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL_FOR_IMAGE_ANALYSIS = 1000;

/** Interface for listening when a weak reference of an instance is removed from the manager. */
public interface FinalizationListener {
void onFinalize(long identifier);
Expand All @@ -58,6 +74,9 @@ public interface FinalizationListener {
private long nextIdentifier = MIN_HOST_CREATED_IDENTIFIER;
private boolean hasFinalizationListenerStopped = false;

private long clearFinalizedWeakReferencesInterval =
DEFAULT_CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL;

/**
* Instantiate a new manager.
*
Expand All @@ -73,8 +92,7 @@ public static InstanceManager create(@NonNull FinalizationListener finalizationL

private InstanceManager(FinalizationListener finalizationListener) {
this.finalizationListener = finalizationListener;
handler.postDelayed(
this::releaseAllFinalizedInstances, CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL);
handler.postDelayed(this::releaseAllFinalizedInstances, clearFinalizedWeakReferencesInterval);
}

/**
Expand Down Expand Up @@ -217,7 +235,19 @@ public boolean hasFinalizationListenerStopped() {
return hasFinalizationListenerStopped;
}

private void releaseAllFinalizedInstances() {
/**
* Modifies the time interval used to define how often this instance removes garbage collected
* weak references to native Android objects that this instance was managing.
*/
public void setClearFinalizedWeakReferencesInterval(long interval) {
clearFinalizedWeakReferencesInterval = interval;
}

/**
* Releases garbage collected weak references to native Android objects that this instance was
* managing.
*/
public void releaseAllFinalizedInstances() {
if (hasFinalizationListenerStopped()) {
return;
}
Expand All @@ -231,8 +261,7 @@ private void releaseAllFinalizedInstances() {
finalizationListener.onFinalize(identifier);
}
}
handler.postDelayed(
this::releaseAllFinalizedInstances, CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL);
handler.postDelayed(this::releaseAllFinalizedInstances, clearFinalizedWeakReferencesInterval);
}

private void addInstance(Object instance, long identifier) {
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera_android_camerax/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: camera_android_camerax
description: Android implementation of the camera plugin using the CameraX library.
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
version: 0.6.2
version: 0.6.3

environment:
sdk: ^3.1.0
Expand Down

0 comments on commit 6f0ed15

Please sign in to comment.