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

Use Service.getObjectId for retaining path. #144

Merged
merged 11 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ class ObjectTracker implements LeakProvider {
final pathSetters = objectsToGetPath.map((code) async {
final record = _objects.notGCed[code]!;
final path =
await obtainRetainingPath(connection, record.type, record.code);
await retainingPathByCode(connection, record.type, record.code);
if (path != null) {
record.setContext(ContextKeys.retainingPath, path);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:developer';
import 'dart:isolate';

import 'package:collection/collection.dart';
import 'package:vm_service/vm_service.dart';
import 'package:vm_service/vm_service.dart' hide Isolate;

import '_connection.dart';

/// Obtains retainig path for an object.
/// Returns retainig path for an object, by identity hash code.
///
/// Does not work for objects that have [identityHashCode] equal to 0.
/// https://github.com/dart-lang/sdk/blob/3e80d29fd6fec56187d651ce22ea81f1e8732214/runtime/vm/object_graph.cc#L1803
Future<RetainingPath?> obtainRetainingPath(
Future<RetainingPath?> retainingPathByCode(
Connection connection,
Type type,
int code,
) async {
final fp = _ObjectFingerprint(type, code);
final theObject = await _objectInIsolate(connection, fp);
final theObject = await _objectInIsolateByFingerprint(connection, fp);
if (theObject == null) return null;

try {
Expand All @@ -35,6 +37,39 @@ Future<RetainingPath?> obtainRetainingPath(
}
}

/// Returns retainig path for an object, if it can be detected.
///
/// If [object] is null or object reference cannot be obtained or isolate cannot be obtained,
/// returns null.
Future<RetainingPath?> retainingPath(
Connection connection,
Object? object,
) async {
if (object == null) return null;

final objRef = Service.getObjectId(object);

if (objRef == null) return null;

try {
final isolateId = Service.getIsolateId(Isolate.current);

if (isolateId == null) {
return null;
}

final result = await connection.service.getRetainingPath(
isolateId,
objRef,
100000,
);

return result;
} on SentinelException {
return null;
}
}

class _ObjectFingerprint {
_ObjectFingerprint(this.type, this.code) : assert(code > 0);

Expand All @@ -54,7 +89,7 @@ class _ObjectFingerprint {
/// This method will NOT find objects, that have [identityHashCode] equal to 0
/// in result of `getInstances`.
/// https://github.com/dart-lang/sdk/blob/3e80d29fd6fec56187d651ce22ea81f1e8732214/runtime/vm/object_graph.cc#L1803
Future<_ItemInIsolate?> _objectInIsolate(
Future<_ItemInIsolate?> _objectInIsolateByFingerprint(
Connection connection,
_ObjectFingerprint object,
) async {
Expand Down
5 changes: 2 additions & 3 deletions pkgs/leak_tracker/lib/src/leak_tracking/helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,9 @@ Future<void> forceGC({
Future<String?> formattedRetainingPath(WeakReference ref) async {
if (ref.target == null) return null;
final connection = await connect();
final path = await obtainRetainingPath(
final path = await retainingPath(
connection,
ref.target.runtimeType,
identityHashCode(ref.target),
ref.target,
);

if (path == null) return null;
Expand Down
4 changes: 2 additions & 2 deletions pkgs/leak_tracker/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: A framework for memory leak tracking for Dart and Flutter applicati
repository: https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker

environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.2.0-162.0.dev <4.0.0'

dependencies:
clock: ^1.1.1
Expand All @@ -13,7 +13,7 @@ dependencies:
logging: ^1.1.1
meta: ^1.8.0
path: ^1.8.3
vm_service: '>=11.3.0 <13.0.0'
vm_service: '>=11.10.0 <13.0.0'
web_socket_channel: ^2.1.0

dev_dependencies:
Expand Down
15 changes: 15 additions & 0 deletions pkgs/leak_tracker/test/tests/leak_tracking/helpers_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2023, 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 'package:leak_tracker/leak_tracker.dart';

import 'package:test/test.dart';

void main() {
test('formattedRetainingPath returns expected path', () async {
final myObject = [1, 2, 3];
final path = await formattedRetainingPath(WeakReference(myObject));
expect(path, contains('dart.core/_GrowableList'));
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void main() {
final instance = MyClass();
final connection = await connect();

final path = await obtainRetainingPath(
final path = await retainingPathByCode(
connection,
instance.runtimeType,
identityHashCode(instance),
Expand All @@ -51,7 +51,7 @@ void main() {
final instance = MyArgClass<String>();
final connection = await connect();

final path = await obtainRetainingPath(
final path = await retainingPathByCode(
connection,
instance.runtimeType,
identityHashCode(instance),
Expand All @@ -65,8 +65,8 @@ void main() {
final connection = await connect();

final obtainers = [
obtainRetainingPath(connection, MyClass, identityHashCode(instance1)),
obtainRetainingPath(connection, MyClass, identityHashCode(instance2)),
retainingPathByCode(connection, MyClass, identityHashCode(instance1)),
retainingPathByCode(connection, MyClass, identityHashCode(instance2)),
];

await Future.wait(obtainers);
Expand Down
2 changes: 1 addition & 1 deletion pkgs/leak_tracker_flutter_testing/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: Flutter specific helpers for dart memory leak tracking.
repository: https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_flutter_testing

environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.2.0-162.0.dev <4.0.0'

dependencies:
flutter:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import 'package:leak_tracker/src/leak_tracking/_primitives/_retaining_path/_conn
import 'package:leak_tracker/src/leak_tracking/_primitives/_retaining_path/_retaining_path.dart';
import 'package:logging/logging.dart';

// We duplicate testing for retaining path here,
// because there were cases when the tests were passing for dart,
// but not for flutter.

class MyClass {
MyClass();
}
Expand Down Expand Up @@ -41,7 +45,7 @@ void main() {
await tester.runAsync(() async {
final connection = await connect();

final path = await obtainRetainingPath(
final path = await retainingPathByCode(
connection,
instance.runtimeType,
identityHashCode(instance),
Expand All @@ -55,7 +59,7 @@ void main() {
final instance = MyArgClass<String>();
final connection = await connect();

final path = await obtainRetainingPath(
final path = await retainingPathByCode(
connection,
instance.runtimeType,
identityHashCode(instance),
Expand All @@ -69,8 +73,8 @@ void main() {
final connection = await connect();

final obtainers = [
obtainRetainingPath(connection, MyClass, identityHashCode(instance1)),
obtainRetainingPath(connection, MyClass, identityHashCode(instance2)),
retainingPathByCode(connection, MyClass, identityHashCode(instance1)),
retainingPathByCode(connection, MyClass, identityHashCode(instance2)),
];

await Future.wait(obtainers);
Expand Down
2 changes: 1 addition & 1 deletion pkgs/leak_tracker_testing/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: Leak tracking code intended for usage in tests.
repository: https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_testing

environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.2.0-162.0.dev <4.0.0'

dependencies:
leak_tracker: '>=9.0.0 <11.0.0'
Expand Down