Reputation: 630
I need to find memory leaks in Flutter. How to find them? and how to create memory leaks for the test?
Upvotes: 33
Views: 39043
Reputation: 1623
I am implemented Memory leak testing in android studio ide.
Step - 1 : Connect your device with android studio and run your application on your device.
Step - 2 :
Go to View
-> Tool Windows
-> Flutter Performance
Step - 3 :
Bottom of the window Open Dev Tools
option will be there, click on it. It will be navigate into new window of your browser.
See below image for more details :
Step - 4 :
To follow the steps below as per the screenshot, you can see the size and details of the object causing the memory leak.
First Select Memory
from available menus than you can able to see below ui.
first: Click on settings
icon
then: Mark down Dart
and Flutter
checkboxes.
and finally: Click on Apply
button.
Step - 5 : This is final step, now you can able to see memory leaking info.
first: Click on Snapshot
it will be collect and display object list in bottom of the window.
and then: Click on search
icon and Here you can see those classes which objects are not destroyed. Suppose am selected ApiRepository.dart
class and instance will be available in memory ,so that details are visible in window. If multiple objects created than you can see here the total no. of instance and total size.
Step - 6 :
You can able to call Garbage Collector manually by using GC
icon . You can anytime Reset and get latest snapshot using Reset
and Snapshot
buttons.
For more information about Memory allocation related details read below articles :
Upvotes: 37
Reputation: 1790
You can start from reading the official documentation - https://docs.flutter.dev/development/tools/devtools/memory
The next steps describe how to run the Memory view and how to create memory leaks manually:
You can simulate significant amount of leaks using the next code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MemoryLeakObject {
final String text;
MemoryLeakObject(this.text);
}
List<MemoryLeakObject> leakObjects = [];
class MemoryLeaksScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CupertinoButton(
child: const Text(
'Create 1 000 000 leaks',
),
onPressed: () {
while (leakObjects.length < 1000000) {
leakObjects.add(
MemoryLeakObject('Count: ${leakObjects.length}'),
);
}
},
),
),
);
}
}
Open the screen with the code above and press the 'Create 1 000 000 leaks' button.
Take a look at the graph again. In my case the "Dart/Flutter" memory usage increased to 101.28 MB. Also a Snapshot was created with all the objects in the memory. As you can see, there are 933365 objects of the "MemoryLeakObject" class.
Upvotes: 10
Reputation: 17567
If you want/need to add non-integration tests to reproduce/fix the memory leak, here is the approach. In short, it runs on your host by simply flutter test
, and does not depend on a simulator/real-device at all.
Example usage: https://gist.github.com/fzyzcjy/e68c375643d7c77942cdc8fb5f01de18
Code (without example):
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'dart:isolate';
import 'package:common_dart/utils/processes.dart';
import 'package:front_log/front_log.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart' hide Isolate, Log;
import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:vm_service/vm_service_io.dart';
const _kTag = 'vm_services';
// #4657
FutureOr<void> runTestsInVmService(
FutureOr<void> Function(VmServiceUtil) body, {
required String selfFilePath,
}) async {
Log.d(_kTag, 'runInVmService selfFilePath=$selfFilePath Platform.script.path=${Platform.script.path}');
if (Platform.script.path == selfFilePath) {
final vmService = await VmServiceUtil.create();
tearDownAll(vmService.dispose);
await body(vmService);
} else {
test(
'run all tests in subprocess',
// #4764
timeout: const Timeout(Duration(seconds: 60)),
() async {
await executeProcess('dart', ['run', '--enable-vm-service', selfFilePath]);
},
);
}
}
/// https://stackoverflow.com/questions/63730179/can-we-force-the-dart-garbage-collector
class VmServiceUtil {
static const _kTag = 'VmServiceUtil';
final VmService vmService;
VmServiceUtil._(this.vmService);
static Future<VmServiceUtil> create() async {
final serverUri = (await Service.getInfo()).serverUri;
if (serverUri == null) {
throw Exception('Cannot find serverUri for VmService. '
'Ensure you run like `dart run --enable-vm-service path/to/your/file.dart`');
}
final vmService = await vmServiceConnectUri(_toWebSocket(serverUri), log: _Log());
return VmServiceUtil._(vmService);
}
void dispose() {
vmService.dispose();
}
Future<void> gc() async {
final isolateId = Service.getIsolateID(Isolate.current)!;
final profile = await vmService.getAllocationProfile(isolateId, gc: true);
Log.d(_kTag, 'gc triggered (heapUsage=${profile.memoryUsage?.heapUsage})');
}
}
String _toWebSocket(Uri uri) {
final pathSegments = [...uri.pathSegments.where((s) => s.isNotEmpty), 'ws'];
return uri.replace(scheme: 'ws', pathSegments: pathSegments).toString();
}
class _Log extends vm_service.Log {
@override
void warning(String message) => Log.w(_kTag, message);
@override
void severe(String message) => Log.e(_kTag, message);
}
Upvotes: 0