Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve code structure. #103

Merged
merged 18 commits into from
Jul 26, 2023
Merged
3 changes: 3 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: CI

# TODO(polina-c): configure auto-update for diagrams
# https://github.com/dart-lang/leak_tracker/issues/104

on:
schedule:
# “At 00:00 (UTC) on Sunday.”
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@ To temporary enable logs, add this line to `main`:
```
Logger.root.onRecord.listen((LogRecord record) => print(record.message));
```

## How to regenerate diagrams

To regenerate diagrams, run:

```
dart run layerlens
```
10 changes: 1 addition & 9 deletions doc/TROUBLESHOOT.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,6 @@ For collecting debugging information in tests, temporarily pass an instance of `
}, leakTrackingTestConfig: LeakTrackingTestConfig.debug());
```

Or, you can temporarily set global flag, to make all tests collecting debug information:

```
setUpAll(() {
LeakTrackerGlobalFlags.collectDebugInformationForLeaks = true;
});
```

**Applications**

For collecting debugging information in your running application, the options are:
Expand Down Expand Up @@ -111,7 +103,7 @@ also become unreachable, and thus available for garbage collection.

One of signs that some leaks still exist is fixing a leak by releasing link to child in the parent's `dispose`,
because link to not needed parent should be released itself, together with its disposal. If
your fix for a leak is like this, you are defenitely hiding leaks of non-tracked objects:
your fix for a leak is like this, you are defenitely hiding leaks of non-tracked objects:

```
void dispose() {
Expand Down
7 changes: 4 additions & 3 deletions examples/minimal_flutter/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import 'package:flutter/material.dart';
import 'package:leak_tracker/leak_tracker.dart';

void main() {
enableLeakTracking();
MemoryAllocations.instance
.addListener((ObjectEvent event) => dispatchObjectEvent(event.toMap()));
LeakTracking.start();
MemoryAllocations.instance.addListener(
(ObjectEvent event) => LeakTracking.dispatchObjectEvent(event.toMap()),
);

runApp(const MyApp());
}
Expand Down
3 changes: 3 additions & 0 deletions pkgs/leak_tracker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# 9.0.0

* Remove global flag [collectDebugInformationForLeaks].
* Rename `checkNonGCed` to `checkNotGCed`.
* Group global items related to leak tracking, in abstract class LeakTracking.
* Rename `gcCountBuffer` to `numberOfGcCycles` and `disposalTimeBuffer` to `disposalTime`.

# 8.0.3
Expand Down
2 changes: 1 addition & 1 deletion pkgs/leak_tracker/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ linter:
# - avoid_bool_literals_in_conditional_expressions # not yet tested
# - avoid_catches_without_on_clauses # we do this commonly
# - avoid_catching_errors # we do this commonly
- avoid_classes_with_only_static_members
# - avoid_classes_with_only_static_members
# - avoid_double_and_int_checks # only useful when targeting JS runtime
- avoid_empty_else
- avoid_field_initializers_in_const_classes
Expand Down
4 changes: 2 additions & 2 deletions pkgs/leak_tracker/example/main.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:leak_tracker/leak_tracker.dart';

void main(List<String> arguments) {
enableLeakTracking();
LeakTracking.start();
// ignore: avoid_print
print('Hello, world!');
disableLeakTracking();
LeakTracking.stop();
}
1 change: 0 additions & 1 deletion pkgs/leak_tracker/lib/DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ Dependencies that create loop are markes with `!`.
flowchart TD;
devtools_integration.dart-->src;
leak_tracker.dart-->src;
testing.dart-->src;
```

4 changes: 2 additions & 2 deletions pkgs/leak_tracker/lib/leak_tracker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

export 'src/leak_tracking/leak_tracker.dart';
export 'src/leak_tracking/leak_tracker_model.dart';
export 'src/leak_tracking/leak_tracking.dart';
export 'src/leak_tracking/model.dart';
export 'src/leak_tracking/orchestration.dart';
export 'src/shared/shared_model.dart';
export 'src/usage_tracking/model.dart';
Expand Down
1 change: 0 additions & 1 deletion pkgs/leak_tracker/lib/src/DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ flowchart TD;
devtools_integration-->shared;
leak_tracking-->devtools_integration;
leak_tracking-->shared;
testing-->shared;
usage_tracking-->shared;
```

Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ bool registerLeakTrackingServiceExtension() => _registerServiceExtension(
/// Registers service extension for DevTools integration.
///
/// If the extension is already registered, returns false.
bool setupDevToolsIntegration(
ObjectRef<LeakProvider?> leakProvider,
bool initializeDevToolsIntegration(
ObjectRef<WeakReference<LeakProvider>?> leakProvider,
) {
Future<ServiceExtensionResponse> handler(
String method,
Expand All @@ -37,7 +37,7 @@ bool setupDevToolsIntegration(
try {
assert(method == memoryLeakTrackingExtensionName);

final theLeakProvider = leakProvider.value;
final theLeakProvider = leakProvider.value?.target;

if (theLeakProvider == null) {
return ResponseFromApp(LeakTrackingTurnedOffError())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'dart:developer';

import 'package:vm_service/vm_service.dart';

import '../leak_tracking/_formatting.dart';
import '../shared/_formatting.dart';
import '_protocol.dart';
import 'primitives.dart';

Expand Down
23 changes: 13 additions & 10 deletions pkgs/leak_tracker/lib/src/leak_tracking/DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ Dependencies that create loop are markes with `!`.
```mermaid
flowchart TD;
_dispatcher.dart-->_object_tracker.dart;
_leak_checker.dart-->leak_tracker_model.dart;
_leak_reporter.dart-->model.dart;
_leak_tracker.dart-->_leak_reporter.dart;
_leak_tracker.dart-->_object_tracker.dart;
_leak_tracker.dart-->model.dart;
_object_record.dart-->_gc_counter.dart;
_object_tracker.dart-->_finalizer.dart;
_object_tracker.dart-->_gc_counter.dart;
_object_tracker.dart-->_object_record.dart;
_object_tracker.dart-->leak_tracker_model.dart;
_object_tracker.dart-->retaining_path;
leak_tracker.dart-->_dispatcher.dart;
leak_tracker.dart-->_leak_checker.dart;
leak_tracker.dart-->_object_tracker.dart;
leak_tracker.dart-->leak_tracker_model.dart;
orchestration.dart-->_gc_counter.dart;
orchestration.dart-->leak_tracker.dart;
orchestration.dart-->leak_tracker_model.dart;
_object_tracker.dart-->_retaining_path;
_object_tracker.dart-->model.dart;
leak_tracking.dart-->_dispatcher.dart;
leak_tracking.dart-->_leak_tracker.dart;
leak_tracking.dart-->model.dart;
orchestration.dart-->_retaining_path;
orchestration.dart-->leak_tracking.dart;
orchestration.dart-->model.dart;
```

Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import 'dart:async';
import '../devtools_integration/delivery.dart';
import '../shared/_util.dart';
import '../shared/shared_model.dart';
import 'leak_tracker_model.dart';
import 'model.dart';

/// Checks [leakProvider] either by schedule or by request.
///
/// If there are leaks, reports them to the enabled outputs:
/// listener, console and DevTools.
class LeakChecker {
LeakChecker({
class LeakReporter {
LeakReporter({
required this.leakProvider,
required this.checkPeriod,
required this.onLeaks,
Expand Down
35 changes: 35 additions & 0 deletions pkgs/leak_tracker/lib/src/leak_tracking/_leak_tracker.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import '_leak_reporter.dart';
import '_object_tracker.dart';
import 'model.dart';

class LeakTracker {
LeakTracker(LeakTrackingConfiguration config) {
objectTracker = ObjectTracker(
leakDiagnosticConfig: config.leakDiagnosticConfig,
disposalTime: config.disposalTime,
numberOfGcCycles: config.numberOfGcCycles,
maxRequestsForRetainingPath: config.maxRequestsForRetainingPath,
);

leakReporter = LeakReporter(
leakProvider: objectTracker,
checkPeriod: config.checkPeriod,
onLeaks: config.onLeaks,
stdoutSink: config.stdoutLeaks ? StdoutSummarySink() : null,
devToolsSink: config.notifyDevTools ? DevToolsSummarySink() : null,
);
}

late final ObjectTracker objectTracker;

late final LeakReporter leakReporter;

void dispose() {
objectTracker.dispose();
leakReporter.dispose();
}
}
11 changes: 7 additions & 4 deletions pkgs/leak_tracker/lib/src/leak_tracking/_object_tracker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import '../shared/shared_model.dart';
import '_finalizer.dart';
import '_gc_counter.dart';
import '_object_record.dart';
import 'leak_tracker_model.dart';
import 'retaining_path/_connection.dart';
import 'retaining_path/_retaining_path.dart';
import '_retaining_path/_connection.dart';
import '_retaining_path/_retaining_path.dart';
import 'model.dart';

/// Keeps collection of object records until
/// disposal and garbage gollection.
Expand All @@ -27,6 +27,7 @@ class ObjectTracker implements LeakProvider {
this.leakDiagnosticConfig = const LeakDiagnosticConfig(),
required this.disposalTime,
required this.numberOfGcCycles,
required this.maxRequestsForRetainingPath,
FinalizerBuilder? finalizerBuilder,
GcCounter? gcCounter,
IdentityHashCoder? coder,
Expand Down Expand Up @@ -54,6 +55,8 @@ class ObjectTracker implements LeakProvider {

final int numberOfGcCycles;

final int? maxRequestsForRetainingPath;

void startTracking(
Object object, {
required Map<String, dynamic>? context,
Expand Down Expand Up @@ -192,7 +195,7 @@ class ObjectTracker implements LeakProvider {

await processIfNeeded(
items: objectsToGetPath,
limit: LeakTrackerGlobalSettings.maxRequestsForRetainingPath,
limit: maxRequestsForRetainingPath,
processor: _addRetainingPath,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ Dependencies that create loop are markes with `!`.

```mermaid
flowchart TD;
_retaining_path.dart-->_service.dart;
_retaining_path.dart-->_connection.dart;
```

Loading