[iOS] 값 형식과 참조 형식

RudinP·2024년 3월 30일
0

Study

목록 보기
214/226

  • 프로그램을 실행할 때마다, OS가 앱을 위한 메모리 공간을 만들어주는데, 여기에 저장된다.
  • 용도에 따라 네가지로 분류한다.

Code

  • 기계어로 번역된 프로그램이 저장됨

Data

  • 정적 변수, 전역 변수가 저장됨
  • 여기에 저장된 데이터는 보통 프로그램 시작 시 만들어지고 프로그램이 끝나면 제거됨

Stack

  • 지역변수, 파라미터, 리턴 값 저장
  • 함수를 호출하면 스택 안에 새로운 메모리 블럭이 만들어짐
  • 스코프에 포함된 모든 값이 여기 저장
    • 이 공간을 스택 프레임이라고 함
    • 함수의 실행이 끝나면 자동으로 사라지고, 이 공간은 다른 함수가 필요할 때 재사용
  • 스택은 스택 프레임을 쌓아가는 방식으로 메모리를 관리
  • 함수를 실행할 때마다 스택 프레임이 추가되고, 반대로 끝나면 최근 스택 프레임부터 순서대로 사라짐

Heap

  • 동적으로 할당한 데이터를 저장하는 공간
  • 동적: 메모리 공간을 직접 만들고 직접 제거한다는 의미
  • 스택은 자동이지만, 힙은 수동이다. 따라서 사용하지 않는 메모리를 그대로 두면 프로그램이 끝날 때까지 계속 남아있다.
    • 이런 메모리공간이 많아지면 사용할 수 있는 메모리 공간이 줄어든다.
    • 이를 메모리 누수, memory leak 이라고 한다.

값 형식과 참조 형식

  • 구조체, 열거형, 튜플은 값 형식
  • 클래스, 클로저는 참조 형식

Value Type

  • 값 형식이 값을 저장하는 공간은 스택
  • 여기에 딱 하나만 저장하고 나머지 공간은 X
  • 함수의 실행이 끝나면 스택 프레임이 사라지면서 연관된 메모리가 자동으로 사라지니 메모리 관리를 따로 하지 않아도 됨
  • 값 형식에서 v1 = v2와 같이 선언한다면, v2의 값이 복사되어 새로운 스택이 만들어지고 이에 v1이 연결된다.(독립적)
    • swift에서는 성능을 높이기 위해 값을 수정할 때만 실제로 복사하도록 최적화
    • Copy on Write

Reference Type

  • 힙과 스택에 하나씩 저장
  • 실제 값은 힙에 저장, 힙의 메모리 주소를 스택에 저장함
  • 값에 접근할 때에는 항상 스택에 있는 주소를 통해 접근
    • 이건 이론적인거고, 코드에서는 그냥 인스턴스 이름으로 접근
  • 대신에 값을 더 이상 사용하지 않는다면, 두 공간에 있는 데이터를 완전히 삭제해서 메모리가 누수되지 않도록 해야함
    • 대부분 자동으로 처리
  • 참조 형식에서 v1 = v2와 같이 선언한다면, 스택에서는 v2의 메모리를 복사하여 새로운 스택에 저장하고, 이를 v1이 가리키게 된다. 다만, 저장된 내용은 v2의 실제 데이터가 있는 Heap의 주소이기 때문에 v1은 스택에서는 v2와 따로 복제되어 존재하지만 같은 Heap 주소를 가리키게 되어 결과적으로는 같은 데이터를 공유한다.(동일 인스턴스)

Copy-on-Write 최적화

  • Value Type에서 v1 = v2를 했을 때 스택에 복사본이 만들어지지 않음
  • 즉, v2의 값이 있는 곳을 v1과도 연결해두고 복사해두지 않음
  • 그러다가 속성을 하나라도 바꾸면 그 때 복사하여 v1과 연결함
  • 값을 읽기만 하면, 복사되지 않으니 메모리를 더 효율적으로 사용 가능

let

  • 인스턴스 자체를 상수로 바꾼다

값 형식일 경우

  • 값 형식에 있는 모든 속성이 상수처럼 값을 바꿀 수 없게 됨
  • 상수와 연결된 스택을 값을 바꾸지 못하는 공간으로 만듦
  • 속성이 변수로 선언되어 있어도 메모리 자체가 수정 불가능하게 잠겨있음
  • 비교 연산자만 사용(==, !=)

참조 형식일 경우

  • 상수와 연결된 스택을 잠그는데, 이는 heap을 가리키는 주소다.
  • 즉, 주소만 변경되지 않도록 잠그기 때문에(가리키는 인스턴스만 바꿀 수 없기 때문에), 속성이 변수로 선언되어 있다면 수정이 가능하다.
  • 값 비교 시 비교 연산자(==, !=)
  • 메모리 주소 비교 시 연산자(===, !==) //항등 연산자

Identity Operator

===, !==

  • 항등 연산자
  • 피연산자는 항상 클래스 인스턴스
  • 항등 연산자 비교 시 동일하면 identical 하다고 하고, 비교 연산자 시 동일하면 equal
profile
곰을 좋아합니다. <a href = "https://github.com/RudinP">github</a>

0개의 댓글