Skip to content

Commit

Permalink
Use Service.getObjectId for retaining path. (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
polina-c authored Sep 20, 2023
1 parent bdf1e6c commit 2f135f3
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 21 deletions.
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

0 comments on commit 2f135f3

Please sign in to comment.