J2ObjC 메모리 모델

이 문서에서는 J2ObjC 변환된 코드에서 메모리가 관리되는 방식과 공유 메모리에 액세스할 때 프로그램이 작동하는 방식을 설명합니다.

메모리 관리

J2ObjC의 목표 중 하나는 Objective-C의 참조 계산 환경에 원활하게 통합되는 번역된 코드를 생성하는 것입니다. 이렇게 하면 자바 및 Objective-C 환경 간에 전달되는 객체에 대한 소유권의 어색한 전환이 없으므로 기본적으로 작성된 Objective-C에서 변환된 자바 코드를 쉽게 사용할 수 있습니다.

자바는 메모리 관리를 위해 가비지 컬렉션을 사용하므로 자바 코드에는 객체의 명시적인 메모리 관리가 포함되지 않습니다. 따라서 J2ObjC는 참조 계산 호출을 적절하게 삽입하여 적절한 시점에 객체가 할당 해제되도록 해야 합니다. 성능 기준에 부합하면서도 실용적인 것으로 확인된 다음과 같은 규칙을 정했습니다.

  • 모든 객체는 최소한 현재 자동 해제 풀 기간 동안 유지됩니다.
    • 이 일반 규칙을 사용하면 다른 방법으로 필요했을 수 있는 많은 보관 및 릴리스를 건너뛸 수 있습니다.
  • 로컬 변수는 유지되지 않습니다.
    • 로컬 변수의 읽기 또는 쓰기에 대한 참조 집계 호출은 없습니다.
  • 필드는 유지됩니다.
    • 필드 할당 호출은 새 값을 유지하고 이전 값은 자동으로 해제됩니다.
  • 새 객체는 즉시 자동 해제됩니다. (필드에 즉시 할당되지 않은 경우)

참조 주기

객체가 필드를 통해 직접 또는 간접적으로 자신을 참조할 때 참조 주기가 존재합니다. 참조 주기는 Java의 가비지 컬렉션으로 정리할 수 있지만 Objective-C의 참조 계산 환경에서는 메모리 누수가 발생합니다. 참조 주기 발생을 방지할 수 있는 자동화된 방법은 없지만, 주기 감지를 자동화하는 주기 찾기 도구를 제공합니다. 참조 주기를 수정하는 일반적인 방법은 다음과 같습니다.

  • @Weak 또는 @WeakOuter 주석을 추가하여 참조 중 하나를 약화합니다.
  • 일부 필드를 null로 설정하는 객체 중 하나에 cleanup() 메서드를 추가합니다. 객체를 삭제하기 전에 cleanup()를 호출합니다.
  • 참조 주기를 완전히 생성하지 않도록 코드를 다시 설계합니다.

공유 메모리

다중 스레드 프로그램에서 일부 데이터는 여러 스레드가 공유할 수 있습니다. Java는 공유 데이터에 대한 스레드 안전 액세스를 허용하는 여러 도구를 제공합니다. 이 섹션에서는 J2ObjC의 공유 데이터 액세스 지원에 대해 설명합니다.

동기식

J2ObjC는 synchronized 키워드를 Objective-C @synchronized에 직접 매핑합니다.

원자성

Java는 longdouble를 제외한 모든 유형의 로드 및 저장에 대해 원자성을 보장합니다. JLS-17.7을 참고하세요. 아래에 설명된 volatile 필드를 제외하고 J2ObjC는 원자적 로드 및 저장을 보장하기 위한 특별한 처리를 제공하지 않습니다. 이는 다음을 의미합니다.

  • 모든 iOS 플랫폼은 32비트 또는 64비트이므로 longdouble를 제외한 기본 유형의 로드 및 저장은 32비트 기기에서 원자적이며, 64비트 시스템에서 모두 원자적입니다.
  • J2ObjC에서 객체 유형의 로드와 저장은 원자적이지 않습니다.
    • 참조 횟수를 원자적으로 업데이트하는 데 비용이 너무 많이 듭니다.
    • 객체 필드는 volatile로 선언하여 원자적으로 만들 수 있습니다. 아래를 참조하세요.

휘발성 필드

volatile 필드의 경우 Java는 동기화에 사용할 수 있는 원자성과 순차적으로 일관된 순서 지정(JLS-8.3.1.4)을 모두 제공합니다. J2ObjC는 모든 volatile 필드에 자바와 동일한 보증을 제공합니다. J2ObjC는 volatile 필드에 다음 메커니즘을 사용합니다.

  • 기본 유형은 c11 원자 유형에 매핑됩니다.
    • 예: volatile int -> _Atomic(jint)
  • 객체 필드는 pthread 뮤텍스 잠금으로 보호됩니다. (우선순위 역전으로 인해 스핀락을 사용할 수 없음)
    • 참조 계산을 통한 경합 상태를 방지하려면 상호 배제가 필요합니다.
    • 이 구현은 Objective-C 원자적 속성과 매우 유사합니다.

원자 유형

자바는 java.util.concurrent.atomic 패키지에서 여러 원자 유형을 제공합니다. 이들은 모두 맞춤 구현을 통해 J2ObjC에서 완벽히 지원됩니다.

최종 필드

Java는 객체를 공유할 때 동기화하지 않고도 스레드가 객체의 최종 필드로 초기화된 값을 볼 수 있도록 보장합니다. (JSL-17.5) 하지만 J2ObjC는 비휘발성 객체 유형의 원자적 액세스를 지원하지 않으므로 (위 참조) 동기화 없이 객체를 공유할 수 있는 안전한 방법은 없습니다. 따라서 최종 필드에 필요한 메모리 펜스를 생략하여 J2ObjC 사용자에게 추가 제약 조건이 적용되지 않습니다.