새 메모리 매니저로 마이그레이션하기

새 메모리 매니저로 마이그레이션하기

이 가이드는 새 Kotlin/Native 메모리 매니저를 기존(레거시) 메모리 매니저와 비교하고, 프로젝트를 어떻게 마이그레이션하는지 설명해요.

출처: Migrate to the new memory manager

본문

새 메모리 매니저에서 가장 눈에 띄는 변화는 객체 공유에 대한 제약이 풀렸다는 것이에요. 스레드 사이에서 객체를 공유하기 위해 더 이상 freeze할 필요가 없어요. 구체적으로는 이렇죠.

  • 최상위(top-level) 프로퍼티는 @SharedImmutable을 쓰지 않고도 어떤 스레드에서든 접근하고 수정할 수 있어요.
  • interop을 통과하는 객체는 freeze하지 않아도 어떤 스레드에서든 접근하고 수정할 수 있어요.
  • Worker.executeAfter는 더 이상 작업이 frozen일 것을 요구하지 않아요.
  • Worker.execute는 더 이상 프로듀서가 격리된 객체 서브그래프를 반환할 것을 요구하지 않아요.
  • AtomicReferenceFreezableAtomicReference를 포함하는 참조 사이클이 메모리 누수를 일으키지 않아요.

쉬워진 객체 공유 외에도 새 메모리 매니저는 다른 큰 변화들을 가져와요.

  • 전역 프로퍼티는 해당 프로퍼티가 정의된 파일에 처음 접근할 때 **지연 초기화(lazily)**돼요. 이전에는 프로그램 시작 시 초기화됐죠. 우회 방법으로는 프로그램 시작 시 반드시 초기화돼야 하는 프로퍼티에 @EagerInitialization 애너테이션을 붙이면 돼요. 사용 전에 문서를 확인하세요.
  • by lazy {} 프로퍼티는 스레드 안전 모드를 지원하며, 무제한 재귀는 처리하지 않아요.
  • Worker.executeAfter 작업에서 빠져나오는 예외는 다른 런타임 부분과 마찬가지로, 사용자가 정의한 처리되지 않은 예외 훅(unhandled exception hook)을 실행하려 시도하거나, 훅을 찾지 못했거나 훅 자체가 예외로 실패하면 프로그램을 종료하는 방식으로 처리돼요.
  • Freezing은 deprecated 처리되었고 항상 비활성화돼요.

레거시 메모리 매니저에서 마이그레이션하려면 다음 지침을 따라 보세요.

코틀린 업데이트

새 Kotlin/Native 메모리 매니저는 Kotlin 1.7.20부터 기본으로 활성화됐어요. 코틀린 버전을 확인하고 필요하면 최신 버전으로 업데이트하세요.

의존성 업데이트

kotlinx.coroutines — 버전 1.6.0 이상으로 업데이트하세요. native-mt 접미사가 붙은 버전은 쓰지 마세요.

새 메모리 매니저와 관련해 짚어둘 특이사항도 몇 가지 있어요.

  • freeze가 필요 없으니 모든 공통 기본 요소(채널, 플로우, 코루틴)가 Worker 경계를 통해 동작해요.
  • Dispatchers.Default는 Linux와 Windows에서는 Worker 풀로, Apple 타깃에서는 전역 큐로 뒷받침돼요.
  • newSingleThreadContext를 사용해 Worker로 뒷받침되는 코루틴 디스패처를 만들어요.
  • newFixedThreadPoolContext를 사용해 N개의 Worker 풀로 뒷받침되는 코루틴 디스패처를 만들어요.
  • Dispatchers.Main은 Darwin에서는 메인 큐로, 그 외 플랫폼에서는 독립형 Worker로 뒷받침돼요.

Ktor — 버전 2.0 이상으로 업데이트하세요.

기타 의존성 — 대부분의 라이브러리는 변경 없이 동작할 거예요. 다만 예외가 있을 수 있어요.

의존성을 최신 버전으로 업데이트하고, 레거시 메모리 매니저와 새 메모리 매니저 사이에서 라이브러리 버전이 다르지 않도록 확인하세요.

코드 업데이트

새 메모리 매니저를 지원하려면 영향받는 API의 사용부를 제거하세요.

기존 API 어떻게 할까요
@SharedImmutable 모든 사용부를 제거하면 돼요. 새 메모리 매니저에서 이 API를 써도 경고는 없어요.
FreezableAtomicReference 클래스 AtomicReference를 대신 사용하세요.
FreezingException 클래스 모든 사용부를 제거하세요.
InvalidMutabilityException 클래스 모든 사용부를 제거하세요.
IncorrectDereferenceException 클래스 모든 사용부를 제거하세요.
freeze() 함수 모든 사용부를 제거하세요.
isFrozen 프로퍼티 모든 사용부를 제거하면 돼요. freezing이 deprecated이므로 이 프로퍼티는 항상 false를 반환해요.
ensureNeverFrozen() 함수 모든 사용부를 제거하세요.
atomicLazy() 함수 lazy()를 대신 사용하세요.
MutableData 클래스 아무 일반 컬렉션이나 대신 사용하세요.
WorkerBoundReference<out T : Any> 클래스 T를 직접 사용하세요.
DetachedObjectGraph<T> 클래스 T를 직접 사용하세요. C interop을 통해 값을 전달하려면 StableRef 클래스를 사용하세요.

다음 단계

  • 새 메모리 매니저에 대해 더 알아보기
  • Swift/Objective-C ARC와의 통합 특이사항 확인하기
  • 서로 다른 코루틴에서 객체를 안전하게 참조하는 방법 배우기

더 알아보기

  • Kotlin/Native 메모리 매니저 문서
  • Swift/Objective-C ARC 연동 문서
  • Kotlin/Native 개요