참조가 어디서 어떻게 될지 미리 알 수 없음.(=컴파일 시점에 알 수 없다.)
스레드 공유 자원이기 때문에 lock과 같은 자원으로 관리가 필요함.
(stack에는 heap 영역의 메모리 주소가 저장된다.)
생성&소멸 시점을 컴파일 시 알 수 있음.
LIFO(Last In Fist Out)
사용이 빠르다. (각 스레드마다 개별의 stack이 존재하기 때문에 상호 배제를 위한 자원이 필요하지 않음.)
> 상호 배제: 같은 자원에 대해 동시 접근 문제가 없도록 제어하는 것.
스택 프레임 종료 시 메모리에서 자동 제거되며, 참조&해제는 pop, push 등 명령어로 쉽게 가능하다.
값 타입도 heap에 저장된다.
값 타입은 heap에 할당되지 않지만, 내부에 참조 타입이 존재하기 때문에 참조 count에 대한 처리가 필요하다.
값 타입이 다른 변수에 할당될 시 copy되어 할당된다.
= 새 메모리 공간에 같은 값 복사
값 타입이 다른 변수에 할당될 시 일단은 메모리 할당을 하지 않고, 같은 곳을 본다.
if-> 해당 값이 변경된다면 이때 메모리에 값을 copy 및 변경
(메모리 최적화를 위해서!)
❗️참조 타입을 포함하는 값 타입의 경우에는 copy-on-write가 적용되지 않는다. 많은 오버헤드가 발생할 수 있기 때문.
let 키워드는 속성의 변경을 불가능하도록 만든다.
let으로 구조체 변수 선언 시 구조체 내부의 속성(프로퍼티)을 변경할 수 없다.
stack 영역의 메모리 공간을 변경하지 못하게 되기 때문이다.
속성을 바꾸다 = stack 메모리의 내용을 바꾸다
(그리고 struct는 stack에 직접 저장된다!)
class의 경우 실제 data는 heap에, stack에는 heap 영역의 메모리 주소가 저장되어 있다. (참조 타입)
따라서 let은 참조 주소(메모리 주소)만 고정시키고, heap에 저장된 내부 내용은 바꿀 수 있다.
class Dog{
var name: String
init(name: String) { self.name = name }
}
let d = Dog(name: "coco")
d.name = "moonazn" // 가능❗️