12

I have a problem about memory with flutter app, when using compute, I put this line in the function parameter in compute:

var image = imglib.Image.fromBytes(values[1].width, values[1].height, values[1].planes[0].bytes, format: imglib.Format.bgra);

And run it in loop, the memory keep growing everytime then out of memory and the app crashed.

If I don't have that line, the memory is stable at 40mb. So I think that in compute, it's not been cleaned up after the compute function finish.

Anyone have same problem?

Edit:

This is how I implement compute:

image = await compute(getCropImage, [copyFaces, streamImg]);

In getCropImage:

Future<imglib.Image> getCropImage(List<dynamic> values) async {
  var image = imglib.Image.fromBytes(values[1].width, values[1].height, values[1].planes[0].bytes, format: imglib.Format.bgra);

  double topLeftX = values[0][0].boundingBox.topLeft.dx.round() -
  (values[0][0].boundingBox.width * 0.2);
  double topLeftY = values[0][0].boundingBox.topLeft.dy.round() -
  (values[0][0].boundingBox.height * 0.2);
  double width = values[0][0].boundingBox.width.round() +
  (values[0][0].boundingBox.width * 0.4);
  double height = values[0][0].boundingBox.height.round() +
  (values[0][0].boundingBox.height * 0.4);
  if (topLeftX <= 0) {
    topLeftX = 25;
  }
  if (topLeftY <= 0) {
    topLeftY = 25;
  }
  if ((topLeftX + width) >= values[1].width) {
    width = values[1].width - topLeftX - 25;
  }
  if ((topLeftY + height) >= values[1].height) {
    height = values[1].height - topLeftY - 25;
  }

  return imglib.copyCrop(
      image, topLeftX.round(), topLeftY.round(), width.round(), height.round());
}

With imglib is the Image package:

import 'package:image/image.dart' as imglib;

Everytime I call this, the memory keep growing.

hoangquyy
  • 1,893
  • 2
  • 14
  • 29
  • Can you share more code? Especially the compute method. – Mehmet Esen Oct 31 '19 at 14:09
  • I have added the code in edit, check it out. Thanks for reply me. @EsenMehmet – hoangquyy Nov 01 '19 at 02:15
  • What is compute method? What is imglib? Can you, please, add more details? – Igor Kharakhordin Nov 03 '19 at 10:24
  • You can read compute method here: https://api.flutter.dev/flutter/foundation/compute.html, that is not my implement function, I just use it. imglib is the package Image: https://pub.dev/packages/image. Sorry my bad @IgorKharakhordin – hoangquyy Nov 04 '19 at 02:08
  • I don't see any problem in your code. Every time you call Image constructor bytearray gets copied, so the memory usage grows. If you think there's a memory issue, you can test it. Try to fill the memory, leave it unused in code (out of scope) and call Garbage Collector manually (you can do it using profiling tools). – Igor Kharakhordin Nov 04 '19 at 03:49
  • Yeah i can see that it not have any problem with my code. That why it is called issue. Even I use manual GC, the memory is still growing and not be released. I have already test it all, if it is easy as you think so I don't have to open bounty. Anyway, thanks for reply – hoangquyy Nov 04 '19 at 04:14
  • Well, I don't think that it is a question for stackoverflow then. Especially if you're sure that your code is correct and there's something wrong with framework. You should probably report an issue in flutter's github. – Igor Kharakhordin Nov 04 '19 at 14:43
  • @IgorKharakhordin I have reported the issue to flutter github for a week but still no reply then. They have so many open issue now. – hoangquyy Nov 05 '19 at 02:04
  • 1
    I think that the `var image` in the first line of the `getCropImage(...)` isn't release after the use, so try using `var image` as field (in order to not allocate always new memory), maybe can be useful to not instantiate a new var at every loop step! Always try to reuse these types of objects, especially when you are managing with big objects such as images. Generally the garbage collector doesn't guarantee to free all unused objects. And remember, never call `System.gc() ` or similar methods directly (to force memory deallocation), that's symptom of broken and not optimized code. :) – Roberto Manfreda Nov 05 '19 at 11:25
  • @RobertoManfreda Thanks you for advise. I'll try it. – hoangquyy Nov 05 '19 at 15:32
  • @hoangquyy, do you still have a link to the issue you filed at flutter/issues? And did Roberto's suggestion work? – TWL Dec 09 '19 at 18:12
  • @TWL Yes I have (https://github.com/flutter/flutter/issues/43623) but it still not have any respond until now. Roberto's suggestion is not work for me but it's a good tip for me anyway. At the end, I don't use isolate anymore. My solution is: I create a channel to the native android and after everything is done, just send back the result to flutter. It's really faster, no more memory leak but the UI is still a little bit lagging. – hoangquyy Dec 10 '19 at 02:16
  • This is likely an issue with https://pub.dev/packages/image itself and not with compute/isolate. You might be able to confirm if you test run `getCropImage()` separately multiple times and see if the memory still grows out of control. – TWL Dec 12 '19 at 19:52

2 Answers2

1

To try to reproduce with your sample, I had to convert from a ui.Image first:

Future<Uint8List> _bytePng(ui.Image image) async {
  ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
  Uint8List byteList = byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes);
  return byteList;
}

The run a simplified version of your sample:

imglib.Image image2 = await compute(_getImage, [image1.width, image1.height, byteList]);


Future<imglib.Image> _getImage(List<dynamic> values) async {
  var temp = imglib.Image.fromBytes(values[0], values[1], values[2], format: imglib.Format.bgra);

  var rng = new Random().nextInt(50);
  imglib.Image cropped = imglib.copyCrop(temp, 0, 0, temp.width - rng, temp.height - rng);

  return cropped;
}

But I wasn't able to see the memory go out of control. So you probably have something else going on.

TWL
  • 6,228
  • 29
  • 65
  • Have you checked the memory in Profile mode? Which version of flutter you are using? I am not sure but maybe it came from flutter version. Someone have same problem as me: - https://stackoverflow.com/questions/57826962/flutter-isolate-image-manipulation-memory-issue – hoangquyy Dec 24 '19 at 02:05
  • And here: https://stackoverflow.com/questions/55695119/flutter-compute-memory-leak-how-do-i-retire-heap-variables-used-by-compute-i – hoangquyy Dec 24 '19 at 02:06
  • So I think the problem not came from my code. I have used other way to solved this problem but not using isolate anymore. However, it's good to solve this memory issue, thanks you. – hoangquyy Dec 24 '19 at 02:09
0

For a starter like us, we need to understand that compute function is nothing but the isolate itself. and the more you call to create isolate the more memory you will be needing. This reference Isolates spawn will take ~ 2mb of ram and so we need to make isolates as less as possible even though you might say that I'm just computing and returning result so isolate might get GC call but no at a time you might be scrolling and caching or doing something with isolate or your code within that isolate can impact huge in-memory footprint.

so rather doing that I suggest you create one isolate and do whatever stuff you want to do and when you finish all you copy faces then close the isolate.

watch this video also to know how to use isolate

Parth Dave
  • 2,096
  • 13
  • 20