getx icon indicating copy to clipboard operation
getx copied to clipboard

Memory leak

Open tooodooo opened this issue 10 months ago • 6 comments

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

tooodooo avatar Apr 18 '25 03:04 tooodooo

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

git-boya avatar May 08 '25 01:05 git-boya

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

  1. sometimes it does not dispose properly. It's a known issue: https://github.com/jonataslaw/getx/issues/961
  2. sometimes the controller gets re-instantiated immediately after disposal

alex-lechner avatar May 20 '25 20:05 alex-lechner

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

  1. sometimes it does not dispose properly. It's a known issue: getxController isn't being disposed/deleted when it should be #961
  2. sometimes the controller gets re-instantiated immediately after disposal

does't work.

tooodooo avatar May 21 '25 04:05 tooodooo

get: ^4.7.2

First entry: Image

Second entry: Image After controller deleted from memory, The RxList<QuestionEntity> in the controller has not released, Obx and Stream counts is also increasing!

git-boya avatar May 21 '25 05:05 git-boya

@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) .

alex-lechner avatar May 21 '25 10:05 alex-lechner

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

hoangsang17th avatar May 23 '25 02:05 hoangsang17th