Skip to content

Commit 6b3efe2

Browse files
Add releaseMemory functionality to DevTools screen controllers (#8997)
1 parent 03c7a99 commit 6b3efe2

23 files changed

Lines changed: 541 additions & 37 deletions

File tree

packages/devtools_app/lib/src/screens/app_size/app_size_controller.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import 'package:vm_snapshot_analysis/utils.dart';
1111
import 'package:vm_snapshot_analysis/v8_profile.dart';
1212

1313
import '../../shared/charts/treemap.dart';
14+
import '../../shared/feature_flags.dart';
15+
import '../../shared/framework/screen.dart';
1416
import '../../shared/framework/screen_controllers.dart';
1517
import '../../shared/primitives/utils.dart';
1618
import '../../shared/table/table.dart';
@@ -85,6 +87,9 @@ class DiffTreeMap {
8587
/// `screenControllers`. The `dispose` method is called by `screenControllers`
8688
/// when DevTools is destroying a set of DevTools screen controllers.
8789
class AppSizeController extends DevToolsScreenController {
90+
@override
91+
final screenId = ScreenMetaData.appSize.id;
92+
8893
static const unsupportedFileTypeError =
8994
'Failed to load size analysis file: file type not supported.\n\n'
9095
'The app size tool supports Dart AOT v8 snapshots, instruction sizes, '
@@ -766,6 +771,16 @@ class AppSizeController extends DevToolsScreenController {
766771
_processingNotifier.dispose();
767772
super.dispose();
768773
}
774+
775+
@override
776+
void releaseMemory({bool partial = false}) {
777+
if (FeatureFlags.memoryObserver) {
778+
// This behavior is the same regardless of the value of `partial`. We can
779+
// implement a partial clearing if it becomes necessary.
780+
clear(AppSizeScreen.analysisTabKey);
781+
clear(AppSizeScreen.diffTabKey);
782+
}
783+
}
769784
}
770785

771786
extension AppSizeJsonFileExtension on DevToolsJsonFile {

packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import '../../shared/diagnostics/primitives/source_location.dart';
2121
import '../../shared/diagnostics/tree_builder.dart';
2222
import '../../shared/feature_flags.dart';
2323
import '../../shared/framework/routing.dart';
24+
import '../../shared/framework/screen.dart';
2425
import '../../shared/framework/screen_controllers.dart';
2526
import '../../shared/globals.dart';
2627
import '../../shared/primitives/message_bus.dart';
@@ -58,6 +59,9 @@ class DebuggerController extends DevToolsScreenController
5859
}
5960
}
6061

62+
@override
63+
final screenId = ScreenMetaData.debugger.id;
64+
6165
@override
6266
void init() {
6367
super.init();

packages/devtools_app/lib/src/screens/deep_link_validation/deep_links_controller.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import '../../shared/analytics/analytics.dart' as ga;
1414
import '../../shared/analytics/constants.dart' as gac;
1515
import '../../shared/analytics/metrics.dart';
1616
import '../../shared/feature_flags.dart';
17+
import '../../shared/framework/screen.dart';
1718
import '../../shared/framework/screen_controllers.dart';
1819
import '../../shared/globals.dart';
1920
import '../../shared/primitives/utils.dart';
@@ -158,6 +159,9 @@ class DisplayOptions {
158159
/// when DevTools is destroying a set of DevTools screen controllers.
159160
class DeepLinksController extends DevToolsScreenController
160161
with AutoDisposeControllerMixin {
162+
@override
163+
final screenId = ScreenMetaData.deepLinks.id;
164+
161165
@override
162166
void dispose() {
163167
_selectedAndroidVariantIndex.dispose();

packages/devtools_app/lib/src/screens/inspector_shared/inspector_screen_controller.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import '../../shared/analytics/metrics.dart';
66
import '../../shared/console/primitives/simple_items.dart';
7+
import '../../shared/framework/screen.dart';
78
import '../../shared/framework/screen_controllers.dart';
89
import '../inspector/inspector_controller.dart' as legacy;
910
import '../inspector/inspector_tree_controller.dart' as legacy;
@@ -21,6 +22,9 @@ import '../inspector_v2/inspector_tree_controller.dart' as v2;
2122
/// `screenControllers`. The `dispose` method is called by `screenControllers`
2223
/// when DevTools is destroying a set of DevTools screen controllers.
2324
class InspectorScreenController extends DevToolsScreenController {
25+
@override
26+
final screenId = ScreenMetaData.inspector.id;
27+
2428
late v2.InspectorController v2InspectorController;
2529
late v2.InspectorTreeController v2InspectorTreeController;
2630

packages/devtools_app/lib/src/screens/logging/logging_controller.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import 'package:vm_service/vm_service.dart';
1818
import '../../service/vm_service_wrapper.dart';
1919
import '../../shared/diagnostics/diagnostics_node.dart';
2020
import '../../shared/diagnostics/inspector_service.dart';
21+
import '../../shared/feature_flags.dart';
2122
import '../../shared/framework/app_error_handling.dart' as error_handling;
23+
import '../../shared/framework/screen.dart';
2224
import '../../shared/framework/screen_controllers.dart';
2325
import '../../shared/globals.dart';
2426
import '../../shared/primitives/byte_utils.dart';
@@ -98,6 +100,9 @@ class LoggingController extends DevToolsScreenController
98100
SearchControllerMixin<LogData>,
99101
FilterControllerMixin<LogData>,
100102
AutoDisposeControllerMixin {
103+
@override
104+
final screenId = ScreenMetaData.logging.id;
105+
101106
static const _minLogLevelFilterId = 'min-log-level';
102107
static const _verboseFlutterFrameworkFilterId = 'verbose-flutter-framework';
103108
static const _verboseFlutterServiceFilterId = 'verbose-flutter-service';
@@ -787,6 +792,18 @@ class LoggingController extends DevToolsScreenController
787792
data.where((log) => includeLogForFilter(log, filter: filter)).toList(),
788793
);
789794
}
795+
796+
@override
797+
void releaseMemory({bool partial = false}) {
798+
if (FeatureFlags.memoryObserver) {
799+
if (partial) {
800+
// Trim logs from the front so that the oldest logs are removed.
801+
_updateData(data.sublist(data.length ~/ 2));
802+
} else {
803+
clear();
804+
}
805+
}
806+
}
790807
}
791808

792809
extension type _LogRecord(Map<String, dynamic> json) {

packages/devtools_app/lib/src/screens/memory/framework/memory_controller.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'dart:async';
1010
import 'package:devtools_app_shared/utils.dart';
1111
import 'package:flutter/foundation.dart';
1212

13+
import '../../../shared/feature_flags.dart';
1314
import '../../../shared/framework/screen.dart';
1415
import '../../../shared/framework/screen_controllers.dart';
1516
import '../../../shared/globals.dart';
@@ -39,6 +40,9 @@ class MemoryController extends DevToolsScreenController
3940
with
4041
AutoDisposeControllerMixin,
4142
OfflineScreenControllerMixin<OfflineMemoryData> {
43+
@override
44+
final screenId = ScreenMetaData.memory.id;
45+
4246
Future<void> get initialized => _initialized.future;
4347
final _initialized = Completer<void>();
4448

@@ -210,4 +214,14 @@ class MemoryController extends DevToolsScreenController
210214
_gcing.value = false;
211215
}
212216
}
217+
218+
@override
219+
FutureOr<void> releaseMemory({bool partial = false}) async {
220+
if (FeatureFlags.memoryObserver) {
221+
diff.clearSnapshots(partial: partial);
222+
// Clear all allocation traces since the traces form a single tracing
223+
// profile.
224+
await trace?.clear();
225+
}
226+
}
213227
}

packages/devtools_app/lib/src/screens/memory/panes/diff/controller/diff_pane_controller.dart

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,24 @@ class DiffPaneController extends DisposableController with Serializable {
151151
}
152152
}
153153

154-
void clearSnapshots() {
154+
void clearSnapshots({bool partial = false}) {
155+
const offsetForInstructionSnapshot = 1;
155156
final snapshots = core._snapshots;
156-
for (var i = 1; i < snapshots.value.length; i++) {
157+
final snapshotsToRemove = max(
158+
offsetForInstructionSnapshot,
159+
(snapshots.value.length - offsetForInstructionSnapshot) ~/
160+
(partial ? 2 : 1),
161+
);
162+
final endIndexToRemoveExclusive =
163+
offsetForInstructionSnapshot + snapshotsToRemove;
164+
for (
165+
var i = offsetForInstructionSnapshot;
166+
i < endIndexToRemoveExclusive;
167+
i++
168+
) {
157169
snapshots.value[i].dispose();
158170
}
159-
snapshots.removeRange(1, snapshots.value.length);
171+
snapshots.removeRange(1, endIndexToRemoveExclusive);
160172
core._selectedSnapshotIndex.value = 0;
161173
derived._updateValues();
162174
}

packages/devtools_app/lib/src/screens/network/network_controller.dart

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import 'package:vm_service/vm_service.dart';
1111

1212
import '../../shared/config_specific/import_export/import_export.dart';
1313
import '../../shared/config_specific/logger/allowed_error.dart';
14+
import '../../shared/feature_flags.dart';
15+
import '../../shared/framework/screen.dart';
1416
import '../../shared/framework/screen_controllers.dart';
1517
import '../../shared/globals.dart';
1618
import '../../shared/http/http_request_data.dart';
@@ -61,6 +63,9 @@ class NetworkController extends DevToolsScreenController
6163
FilterControllerMixin<NetworkRequest>,
6264
OfflineScreenControllerMixin,
6365
AutoDisposeControllerMixin {
66+
@override
67+
final screenId = ScreenMetaData.network.id;
68+
6469
List<DartIOHttpRequestData>? _httpRequests;
6570

6671
Future<String?> exportAsHarFile() async {
@@ -392,9 +397,11 @@ class NetworkController extends DevToolsScreenController
392397

393398
/// Clears the HTTP profile and socket profile from the vm, and resets the
394399
/// last refresh timestamp to the current time.
395-
Future<void> clear() async {
396-
await networkService.clearData();
397-
_currentNetworkRequests.clear();
400+
Future<void> clear({bool partial = false}) async {
401+
if (!partial) {
402+
await networkService.clearData();
403+
}
404+
_currentNetworkRequests.clear(partial: partial);
398405
_filterAndRefreshSearchMatches();
399406
_updateSelection();
400407
}
@@ -507,6 +514,13 @@ class NetworkController extends DevToolsScreenController
507514
.whereType<DartIOHttpRequestData>()
508515
.map((item) => item.getFullRequestData())
509516
.wait;
517+
518+
@override
519+
FutureOr<void> releaseMemory({bool partial = false}) async {
520+
if (FeatureFlags.memoryObserver) {
521+
await clear(partial: partial);
522+
}
523+
}
510524
}
511525

512526
/// Class for managing the set of all current sockets, and
@@ -589,9 +603,19 @@ class CurrentNetworkRequests extends ValueNotifier<List<NetworkRequest>> {
589603
}
590604
}
591605

592-
void clear() {
593-
_requestsById.clear();
594-
value = [];
595-
notifyListeners();
606+
void clear({bool partial = false}) {
607+
if (partial) {
608+
_requestsById.keys
609+
.toList()
610+
// Trim requests from the front so that the oldest data is removed.
611+
.sublist(0, _requestsById.keys.length ~/ 2)
612+
.forEach(_requestsById.remove);
613+
value = value.sublist(value.length ~/ 2);
614+
notifyListeners();
615+
} else {
616+
_requestsById.clear();
617+
value = [];
618+
notifyListeners();
619+
}
596620
}
597621
}

packages/devtools_app/lib/src/screens/performance/panes/flutter_frames/flutter_frames_controller.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,13 @@ class FlutterFramesController extends PerformanceFeatureController {
171171
}
172172

173173
@override
174-
void clearData() {
175-
_flutterFrames.clear();
174+
void clearData({bool partial = false}) {
175+
if (partial) {
176+
// Trim frames from the front so that the oldest logs are removed.
177+
_flutterFrames.trimToSublist(_flutterFrames.value.length ~/ 2);
178+
} else {
179+
_flutterFrames.clear();
180+
}
176181
_unassignedFlutterFrames.clear();
177182
firstWellFormedFrameMicros = null;
178183
_selectedFrameNotifier.value = null;

packages/devtools_app/lib/src/screens/performance/panes/rebuild_stats/rebuild_stats_controller.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class RebuildStatsController extends PerformanceFeatureController {
1616
RebuildStatsController(super.performanceController);
1717

1818
@override
19-
FutureOr<void> clearData() {}
19+
void clearData({bool partial = false}) {}
2020

2121
@override
2222
void handleSelectedFrame(FlutterFrame frame) {}

0 commit comments

Comments
 (0)