Memory leak
Here is the sample code used:
example:
import 'package:demo/home.dart';
import 'package:flutter/material.dart';
import 'package:get/get_navigation/src/root/get_material_app.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: HomeView(),
);
}
}
import 'package:demo/bview.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class HomeView extends StatelessWidget {
const HomeView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Test")),
body: Center(
child: FilledButton(
onPressed: () {
Get.to(() => Bview());
},
child: Text("GO"),
),
),
);
}
}
import 'package:demo/blogic.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Bview extends StatelessWidget {
const Bview({super.key});
@override
Widget build(BuildContext context) {
Blogic logic = Get.put(Blogic());
return Scaffold(
appBar: AppBar(title: Text("BView")),
body: Center(child: Obx(() => Text(logic.test.value))),
);
}
}
import 'package:get/state_manager.dart';
class Blogic extends GetxController {
final test = "abc".obs;
}
To Reproduce Check the number of class instances in the DevTools memory. If the Obx is not used in BView, BView can be normally reclaimed by the GC (Garbage Collector). However, when Obx is used, BView cannot be reclaimed by the GC, and the number of instances will keep increasing. BLogic can be normally reclaimed.
Is the usage method incorrect?
I tried to use GetView & GetBuilder, same issure. BView still can not be reclaimed.
Flutter Version: Flutter 3.7.2
Getx Version: get: ^4.7.2
same issue
class Logic extends GetxController {
RxList<Test> testList = RxList();
@override
void onInit() {
super.onInit();
testList(List.filled(10, Test()));
}
}
Repeated entry and exit, infinite increase in Test count, when use Obx
You have to close the observable when disposing the controller:
class Blogic extends GetxController {
final test = "abc".obs;
@override
void onClose() {
test.close();
}
}
Just be careful when using GetxController because
- sometimes it does not dispose properly. It's a known issue: https://github.com/jonataslaw/getx/issues/961
- sometimes the controller gets re-instantiated immediately after disposal
You have to close the observable when disposing the controller:
class Blogic extends GetxController { final test = "abc".obs; @override void onClose() { test.close(); } }Just be careful when using GetxController because
- sometimes it does not dispose properly. It's a known issue: getxController isn't being disposed/deleted when it should be #961
- sometimes the controller gets re-instantiated immediately after disposal
does't work.
get: ^4.7.2
First entry:
Second entry:
After controller deleted from memory,
The RxList<QuestionEntity> in the controller has not released, Obx and Stream counts is also increasing!
@git-boya and @tooodooo
You have to close your Observables. In case of BehaviorSubject you have to do myBehaviorSubject.cancel() and in case of Rx you have to do myRx.close().
[!IMPORTANT] BehaviorSubjects and Rx Observables must all be initialized and disposed inside the controller.
If you do the initialization and disposal properly, you will have no memory leaks - guaranteed! If you still have memory leaks, then it's either because your controller was not disposed properly or you declared your Observables in the UI layer (e.g. StatelessWidget).
I would recommend taking a look at rx_widgets and use, for example, the ReactiveBuilder instead of the Obx widget in the UI layer. It's more mature when you subscribe to observables and want to update the UI accordingly. Obx sometimes throws weird errors or keeps your controller in memory (even though it should not) .
There is no logic in closing the controller. You need to wrap the view by GetBuilder or GetX like that
class Bview extends GetView<Blogic> {
const Bview({super.key});
@override
Widget build(BuildContext context) {
return GetX<UpdateMyWorkspaceViewController>( // <= Replace GetX by GetBuilder if u want
init: Get.put(Blogic()),
builder: (context) {
return Scaffold(
appBar: AppBar(title: const Text("BView")),
body: Center(child: Obx(() => Text(logic.test.value))),
);
},
);
}
}
Or you can close the controller by manually, like Get.delete<Blogic>(); at anywhere that you think the controller need to close