-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
⚡️ Deallocate operations and requests for cancellation #2252
Conversation
Apparently |
test('cancels multiple requests', () async {
final client = MockHttpClient();
CancelToken? token = CancelToken();
final tokenRef = WeakReference(token);
const reason = 'cancel';
final dio = Dio()
..httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () => client,
);
final requests = <MockHttpClientRequest>[];
when(client.openUrl(any, any)).thenAnswer((_) async {
final request = MockHttpClientRequest();
requests.add(request);
when(request.close()).thenAnswer((_) async {
final response = MockHttpClientResponse();
when(response.headers).thenReturn(MockHttpHeaders());
when(response.statusCode).thenReturn(200);
await Future.delayed(const Duration(milliseconds: 200));
return response;
});
return request;
});
final futures = [
dio.get('https://pub.dev', cancelToken: token),
dio.get('https://pub.dev', cancelToken: token),
];
for (final future in futures) {
expectLater(
future,
throwsDioException(
DioExceptionType.cancel,
matcher: isA<DioException>().having(
(e) => e.error,
'error',
reason,
),
),
);
}
await Future.delayed(const Duration(milliseconds: 100));
token.cancel(reason);
expect(requests, hasLength(2));
try {
await Future.wait(futures);
} catch (_) {
// ignore, just waiting here till all futures are completed.
}
for (final request in requests) {
verify(request.abort()).called(1);
}
token = null;
Object? obj = Object();
final objRef = WeakReference(obj);
print(tokenRef.target);
print(objRef.target);
obj = null;
List.generate(
1 * 1024 * 1024,
(index) => Object(),
);
print(tokenRef.target);
print(objRef.target);
expect(objRef.target, isNull);
expect(tokenRef.target, isNull);
});
I rewrite the method of I got next log:
So, I think the cancel token isn't be deallocate in GC. |
BTW, maybe |
e31512b
to
b2b5490
Compare
b2b5490
to
74fd79f
Compare
@kuhnroyal I've also configured the Melos script not to produce coverage outputs when running with the minimum SDK so the min test will not fail because of |
Do you have experience with https://pub.dev/packages/leak_tracker? |
I glanced at those packages, which seemed to not fit the current case and require a significant amount of work. Also not sure if they are compatible with older Dart. Spoken with @CaiJingLong and a stable way to test GC (also in Dart's tests) is generating big objects so here we have 1024 * 1024. This is what I've got so far. |
Signed-off-by: Alex Li <[email protected]>
There is a method in dart's testcase: This method may be more in line with the rules of dart memory allocation. void produceGarbage() {
const approximateWordSize = 4;
List<dynamic> sink = [];
for (int i = 0; i < 500; ++i) {
final filler = i % 2 == 0 ? 1 : sink;
if (i % 250 == 1) {
// 2 x 25 MB in old space.
sink = List.filled(25 * 1024 * 1024 ~/ approximateWordSize, filler);
} else {
// 498 x 50 KB in new space
sink = List.filled(50 * 1024 ~/ approximateWordSize, filler);
}
}
print(sink.hashCode); // Ensure there's real use of the allocation.
} |
Cool, now we can run that test on the minimal SDK requirement too. |
Code Coverage Report: Only Changed Files listed
Minimum allowed coverage is |
Resolve #2111
New Pull Request Checklist
main
branch to avoid conflicts (via merge from master or rebase)CHANGELOG.md
in the corresponding package