“Configuration change 발생 시 MapView로 인한 메모리 누수가 발생합니다”

안녕하세요.

지도를 사용하는 화면에서 Configuration change 발생 시 메모리 누수가 발생하는 현상을 확인하였습니다.

onResume/onPause 시점에 맞춰 MapView.resume(), MapView.pause() 또한 잘 호출하고 있는데, 어떤 원인으로 해당 문제가 발생하는 것인지 알 수 없어 이렇게 여쭙습니다.

LeakCanary 로그:

┬───
│ GC Root: Global variable in native code
│
├─ com.kakao.vectormap.internal.MapViewHolder instance
│    Leaking: UNKNOWN
│    Retaining 346 B in 11 objects
│    ↓ MapViewHolder.mapView
│                    ~~~~~~~
├─ com.kakao.vectormap.MapView instance
│    Leaking: YES (View.mContext references a destroyed activity)
│    Retaining 1.5 kB in 19 objects
│    View is part of a window view hierarchy
│    View.mAttachInfo is null (view detached)
│    View.mID = R.id.mainMap
│    View.mWindowAttachCount = 1
│    mContext instance of com.example.app.presentation.course.CoursesActivity with mDestroyed = true
│    ↓ View.mContext
╰→ com.example.app.presentation.course.CoursesActivity instance
     Leaking: YES (ObjectWatcher was watching this because com.example.app.presentation.course.
     CoursesActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
     Retaining 778.7 kB in 14530 objects
     key = ...
     watchDurationMillis = 5561
     retainedDurationMillis = 561
     mApplication instance of com.example.app.presentation.CoursePickApplication
     mBase instance of androidx.appcompat.view.ContextThemeWrapper

감사합니다.

Configuration change 상황이라고 하셨는데, 올려주신 로그를 보니 destroyed activity 를 참조하여 발생한 메모리릭으로 보여집니다.

  1. Configuration change 시에, 액티비티가 매번 destroy 됐다 새로 생성되는 구조인 것이죠?
  2. 그렇다면, MapView 는 하나의 Activity 에 종속적이므로, Configuration change 가 될 때마다 지도가 제대로 종료되고 새로 생성되는지 확인이 필요하고 이 과정에서 MapView 객체를 Activity 라이프사이클을 벗어나서 어딘가 저장되어 있지 않은지 확인이 필요합니다.
  3. 디버그 모드에서 문제의 상황(Configuration change 발생)을 재현시키시고 “k3f” 로 필터링 된 로그캣 로그 첨부 부탁 드립니다.
1개의 좋아요

우선 MapView#finish 함수를 직접 호출하여 메모리 누수를 방지하였습니다.

다만 finish 함수는 Activity가 종료될 때 자동으로 호출되는데, 해당 에러가 왜 나는건지에 대해서는 알 필요가 있을 것 같아 로그 첨부드립니다!

2025-12-02 18:16:57.324 16633-16769 K3fCore                 io.coursepick.coursepick.dev         I  Engine{1764666997} paused
2025-12-02 18:16:57.336 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         D  onDetachedFromWindow(isFinishing=false)
2025-12-02 18:16:57.376 16633-16822 K3fAApi                 io.coursepick.coursepick.dev         D  ---> RequestHeader(https://dapi.kakao.com/v2/maps/vector/auth) {Accept=[application/json], Authorization=[KakaoAK e5cb62256b681aeb46a0a80aa6f9d3f2], KA=[mapSdk/2.12.8 os/android-36 lang/ko-KR origin/Qpd2MAjN3ezNxnAtVfXlnFjCJeg= device/sdk_gphone64_arm64 android_pkg/io.coursepick.coursepick.dev]}
2025-12-02 18:16:57.404 16633-16822 K3fAApi                 io.coursepick.coursepick.dev         V  <-- {null=[HTTP/1.1 200 OK], Connection=[keep-alive], Content-Length=[0], Content-Type=[application/json], Date=[Tue, 02 Dec 2025 09:16:57 GMT], X-Android-Received-Millis=[1764667017404], X-Android-Response-Source=[NETWORK 200], X-Android-Selected-Protocol=[http/1.1], X-Android-Sent-Millis=[1764667017377], x-request-id=[26d9623d2378d2a94955fef28a641e49]}
2025-12-02 18:16:57.449 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  AppSpec : High spec
2025-12-02 18:16:57.449 16633-16821 K3fCore                 io.coursepick.coursepick.dev         I  app diplay scale: 1.500000
2025-12-02 18:16:57.449 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         V  + e s(2.12.8, 9774c778, 66a7ed9b4 1.500000, io.coursepick.coursepick.dev)
2025-12-02 18:16:57.450 16633-16821 K3fCore                 io.coursepick.coursepick.dev         I  DownloadManager initialized
2025-12-02 18:16:57.464 16633-16821 K3fCore                 io.coursepick.coursepick.dev         I  >>> Initialize appEngine[RELEASE]{1764667017}
2025-12-02 18:16:57.467 16633-16821 K3fCore                 io.coursepick.coursepick.dev         I  >>> Start appEngine[RELEASE]{1764667017}
2025-12-02 18:16:57.467 16633-16821 K3fCore                 io.coursepick.coursepick.dev         I  android high
2025-12-02 18:16:57.470 16633-16821 K3fCore                 io.coursepick.coursepick.dev         I  DownloadManager initialized
2025-12-02 18:16:57.470 16633-16821 K3fCore                 io.coursepick.coursepick.dev         I  start to make a map view
2025-12-02 18:16:57.472 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         V  + e c (1280, 2856, openmap)
2025-12-02 18:16:57.472 16633-16821 K3fCore                 io.coursepick.coursepick.dev         I  Engine{1764667017} resumed.
2025-12-02 18:16:57.472 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         V  - allViewport(1280, 2856)
2025-12-02 18:16:57.576 16633-16821 K3fCore                 io.coursepick.coursepick.dev         E  unsupported image format.
2025-12-02 18:16:57.584 16633-16821 K3fCore                 io.coursepick.coursepick.dev         I  onRenderViewSuccess
2025-12-02 18:16:57.584 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         D  --> RenderView/setLogoPosition(gravity: 9, x: 30.000000, y: 30.000000)
2025-12-02 18:16:57.585 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         V  addTerrainClickListener done.
2025-12-02 18:16:57.585 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         V  addPoiClickEventListener done.
2025-12-02 18:16:57.586 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         D  Added Image. AssetId : [2131230932_dark]
2025-12-02 18:16:57.586 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         E  ImageAsset is invalid.
2025-12-02 18:16:57.586 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         E  ImageAsset is invalid.
2025-12-02 18:16:57.586 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         E  ImageAsset is invalid.
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addLayer(id=route_layer_0, zOrder: 10000) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] removeLayerAllRouteLine(id=route_layer_0) --->
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=190381954_dark) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=156571344_dark) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=185485001_dark) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=119247310_dark) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=8259823_dark) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=71094268_dark) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=237733509_dark) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=25489384_dark) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=203621889_dark) ---> 
2025-12-02 18:16:57.596 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=209980582_dark) ---> 
2025-12-02 18:16:57.597 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         V  <--- onPaddingResized(left: 0, top: 0, right: 0, bottom: 1428)
2025-12-02 18:16:57.597 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  <--- setVirtualViewport(left=0.000000, top=0.000000, right=0.000000, bottom=1428.000000)
2025-12-02 18:16:57.609 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         V  addTerrainClickListener return. already added.
2025-12-02 18:16:57.609 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         V  addPoiClickEventListener return. already added.
2025-12-02 18:16:57.610 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         E  ImageAsset is invalid.
2025-12-02 18:16:57.610 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         E  ImageAsset is invalid.
2025-12-02 18:16:57.610 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         E  ImageAsset is invalid.
2025-12-02 18:16:57.792 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] removeLayerAllRouteLine(id=route_layer_0) --->
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=223628594_dark) ---> 
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=51792515_dark) ---> 
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=260297728_dark) ---> 
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=206712876_dark) ---> 
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=129243893_dark) ---> 
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=107237514_dark) ---> 
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=234653435_dark) ---> 
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=113779480_dark) ---> 
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=175665521_dark) ---> 
2025-12-02 18:16:57.807 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=104786774_dark) ---> 
2025-12-02 18:16:58.105 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         D  Added Image. AssetId : [2131230933_dark]
2025-12-02 18:16:58.106 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Label] addLayer(id=label_default_layer, zOrder=10001, type=0, unit=0, order=0, isLod=0) ---> 
2025-12-02 18:16:58.106 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Label] addLayer(id=lodLabel_default_layer, zOrder=10001, type=0, unit=0, order=0, isLod=1) ---> 
2025-12-02 18:16:58.106 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Label] addPointLabelStyles(id=476605188_dark) ---> 
2025-12-02 18:16:58.106 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Label] addLabel(layer=label_default_layer, styleId=476605188_dark, labelId=2131230933, lsLod=0) ---> 
2025-12-02 18:16:58.112 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  --> newCenterPoint(lat: 37.515292, lng: 127.102985, zoomLevel: -1, height: 5116.503631, animate: 1, duration: 750, makeViaPoint: 1, chain: 0)
2025-12-02 18:16:58.325 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         V  addTerrainClickListener return. already added.
2025-12-02 18:16:58.325 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         V  addPoiClickEventListener return. already added.
2025-12-02 18:16:58.325 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         E  ImageAsset is invalid.
2025-12-02 18:16:58.325 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         E  ImageAsset is invalid.
2025-12-02 18:16:58.325 16633-16633 K3fAApi                 io.coursepick.coursepick.dev         E  ImageAsset is invalid.
2025-12-02 18:16:58.333 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] removeLayerAllRouteLine(id=route_layer_0) --->
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=234374325_dark) ---> 
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=10655562_dark) ---> 
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=210708155_dark) ---> 
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=107128792_dark) ---> 
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=41907095_dark) ---> 
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=54946180_dark) ---> 
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=79611298_dark) ---> 
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=186833769_dark) ---> 
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=149395950_dark) ---> 
2025-12-02 18:16:58.350 16633-16821 K3fAApi                 io.coursepick.coursepick.dev         D  [Route] addRouteStyle(id=127352463_dark) ---> 

확인 후 답변주시면 감사드리겠습니다. :slightly_smiling_face:

올려주신 로그는 지도가 시작(start) 시에 나오는 정상적인 내용들입니다. 아래의 로그는 무시하셔도 괜찮습니다.

ImageAsset is invalid. unsupported image format.

혹시, 지도를 종료했는데도 위의 로그가 나오고 있다면 지도가 어디선가/어떤 부분에 의해 다시 실행된 걸로 보여집니다. 이 부분을 살펴보시면 좋을 것 같습니다.

1개의 좋아요