어제 이분이 cached network image 버그라고 말해줫는데 image network로 고쳐도 메모리누수 문제가 해결되지 않았음




이미지가 2.8기가나 쳐먹는 모습


아래는 메모리 맵인데 ImageCache가 2.4기가인걸 볼 수 있을꺼임

ImageCache는 CachedNetworkImage랑은 다른건데

ImageCache는 램에 올려서 캐싱하는거고 CachedNetworkImage 보조메모리에서 캐싱하는 거임


원래라면 이미지 캐시가 자동으로 이미지를 해제해줘야하는데 그게 동작을 안해서

이미지 캐시 사이즈 조절하고 클리어 함수도 넣어봄


class CustomImageCache extends WidgetsFlutterBinding {
  @override
  ImageCache createImageCache() {
    ImageCache imageCache = super.createImageCache();
    // Set your image cache size
    imageCache.maximumSizeBytes = 1024 * 1024 * 100; // 100 MB
    imageCache.maximumSize = 10;
    // print('cic');
    return imageCache;
  }
}


    imageCache.maximumSizeBytes = 1024 * 1024 * 100; // 100 MB
    imageCache.maximumSize = 10;


    PaintingBinding.instance.imageCache.clear();


관련 문제들 찾아봐서 이런 코드들 추가해줬는데 아예 동작을 안함

image.network나 networkimage나 cachednetworkimage 전부다


저 메모리맵에서 확대해보면

이러함

ImageCache의 _LiveImage가 2.3GB임. _pendingImages랑 _cache가 같이있는걸 보면 _LiveImage는 지금 활성 중인 이미지를 말하는 것 같음

다시 확대해보면 MultiImageStreamCompleter => ImageInfo => Image가 2.3GB를 먹고 있음

https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/painting/image_stream.dart#L592

대충 이미지 스케쥴링하고 관리해주는 GC같은 역할 인 것 같음


이제 문제는 두 가지로 좁혀짐

1. _LiveImage가 적절하게 _Cache로 들어가지 않는다

2. 추적되지 않는 미지의 공간에 ImageCache 인스턴스가 존재한다.


2. 일단 이건 아님. imagecache는 하나밖에 없었음


1.

해결방법은 진짜 단순한데 clearLiveImages이걸 호출하면됨

근데 다른 이미지들까지 다 지워진다는 문제가 있어서 별로 좋은 건 아님

다른 방법으로는 꼭 지워야되는 이미지들의 key를 다 저장한다음에 imagecache에서 live한 이미지를 싹다 지우는거임


이거는 그냥 단순무식한 해결방법이고, 진짜 문제는 왜 자동으로 cache되지 않는가임


clear 함수를 보면 _cache랑 pending은 지워주는데 live는 안지워줌

그렇다면 live하지 않은 이미지는 _liveImage에서 _cache로 이동시켜주는 함수가 있을꺼임

찾아보니깐 evict라는 함수가 있음

근데 evict는 cache에 넣는게 아니라 아예 live에서 삭제시켜버림

_touch라는 함수가 있는데 이게 live에서 cache로 옮겨주는 함수 같음

_touch는 putIfAbsent에서 호출되는데 putIfAbsent는 live한 이미지를 cache에다 넣고 completer를 리턴함

putIfAbsent는 ImageProvider의 resolveStreamForKey메서드에서만 호출됨

resolveStreamForKey는 resolve에서 호출됨

resolve를 보면 configuration이 실패하면 resolveStreamForKey가 호출되지 않음

그러면 resolve를 하는 메서드들 중에 configuration이 실패하는 것들을 찾아보면 될 것 같음

내 뷰어에 있는 이미지 크기를 가져오는 함수임

여기에 resolve가 있음

이제 문제가 뭔지 대충 알 수 있는데, _calculateImageDimension은 live한 이미지를 cache로 보내고,

Image.network는 live한 이미지가 필요한 애들임

만약에 이 두 과정이 thread safe하지 않는다면 cache랑 live 모두에 존재해서 cache를 아무리 지워대도 live에 계속 살아있어서 없어지지 않는 다는 결론이 나옴


근데 _calculateImageDimension 지우고 다시 테스트해봤는데 이거 문제도 아닌듯 ㅡ,ㅡ

뭔지 모르겠음

걍 PaintingBinding.instance.imageCache.clearLiveImages(); 이거 추가함

문제 해결