메모리 관리는 어떻게 해야하는걸까? 그 전에 메모리 관리는 왜 해야하는걸까?
당연히 효율적인 접근은 중요하고, 프로그램 또는 어플이 잘 돌아가는 것은 더더욱 중요하다.
하지만 요즘은 기본 메모리가 필요 이상으로 많지 않나??
노래 듣기 위해 사용하던 mp3는 1gb에서 어느새 아이폰 기준, 256gb가 기본 용량이 되었고 2000년대 초반까지 256mb였던 '기본 RAM' 크기는 2015년 이후부터 16gb가 되었다고 한다.
이렇게 기술이 좋아지는 상황에서 조금 더 메모리를 사용하더라도 크게 문제가 될까?
이 생각에서 시작하게 된 메모리 관련해서 내용을 정리해보고자 한다.
우선 Swift는 ARC, strong, weak, unowned, 디버깅 툴 등 다양한 기술과 방법으로 메모리 관리가 가능하다.
여기서 '메모리'는 무엇일까?
메모리는 컴퓨터가 방대한 정보를 일일히 확인하느라 시간과 에너지를 소비하지 않도록 저장해두는 일종의 설명서와 정보라고 볼 수 있다. 메모리 덕분에 특정 정보를 빠르게 찾아볼 수 있으며 원하는 프로그램들을 실행할 수 있게 된다.
이를 흔히 컴퓨터 메모리라 부르는데 RAM, SSD, HDD 등이 포함된다!
RAM, SSD, HDD를 대략 정리하면,
속도는 RAM > SSD > HDD 순이지만 용량은 HDD > SSD > RAM 순이다.
RAM은 비교불가 수준으로 빠른 접근 및 전달이 가능하지만 용량이 크지 않는 이유는
① 파워가 끊길 경우 데이터를 모두 날리는 특징과
② 비효율성 때문이라고~
RAM이 거대하더라도 그만큼 필요로 하는 작업 자체가 없다고 한다.
이렇게 메모리를 간단하게 둘러봤다!
그렇다면 도대체 왜 메모리 관리가 중요할까?
개발자로써 왜 메모리 관리를 해야할까?
결국 개발자는 해당 프로그램을 많은 사람들이 사용할 수 있도록 만들어야 하기 때문이 아닐까 싶다.
만든 어플에서 메모리 누수가 계속 발생해서 500mb ~ 이상 메모리를 잡아먹는다고 가정해보자.
최근 아이폰을 구매한 사용자도, 오랜 기간동안 한 기종만 사용하던 사용자도 모두 사용은 할 수 있겠다.
하지만 시간이 지나면서 다른 어플, 프로그램 등을 다운받고 실행한 이후에 우리 프로그램을 돌릴 수 있을까?
사용자들의 아이폰이 어떠한 상황에 있더라도 실행이 되기 위해서는 아이폰에서 열릴 수 있어야 한다.
그렇게 하기 위해선 효율적인 메모리 관리가 필요하지 않을까 생각된다.
*한 예로 슈퍼 마리오 게임 개발에는 총 40kb 메모리를 사용했다고 한다. 물론 당시에는 최대 성능이긴 했지만;;; 게임 개발자들은 해당 용량에 한 게임을 담아내야 했던만큼 아트웍, 팔레트 등을 재활용했다고 한다. 덕분에 한 사진보다 적은 용량에 게임이 다 담기게 되었는데... 지금도 마찬가지라 볼 수 있다!
결국 목적은 다양한 상황에 있는 많은 사람들에게 동일한 경험을 선사하기 위한 하나의 이유로 메모리를 효율적으로 관리 해야한다. 더군다나 따로 관리를 하지 않을 경우 메모리를 유지하는 것 자체가 어려운데, 별도의 툴 없이는 Memory Leak, Zombie, Hang 등 다양한 이유와 원인이 발목을 붙잡게 된다.
그렇다면 Swift에서는 어떻게 메모리를 관리할까?
지금은 ARC를 통해 자동적으로 메모리로 올리고 내리게 되는데, ARC 이전에는 모두 개발자가 수동으로 관리를 해야했다.
*지금도 엄밀히 말하면 동일하게 진행이 되지만 뒷단에서 실행되기에 개발자 눈에는 안 보이는 것 뿐
Manual Memory Management
새로운 객체가 생성될 때마다 메모리에 올릴지, 내릴지 구분을 하고 생성한 객체의 값을 활용하는 시점을 파악해야 했는데, 올리는 작업은 allocation, 내리는 작업은 deallocation 그리고 객체 값을 활용하기 위해 생성된 pointer라고 부른다.
여기서 pointer는 그저 메모리의 주소를 담고 가리키는 정보인데, 메모리 접근을 더 쉽게 도와줄 뿐 - 그 이상 그 이하도 아니라고 한다. 몰랐던 점은 dereferencing pointer의 개념이다. 이는 포인터가 가리키는 메모리 주소가 아닌 실제 해당 메모리 주소에 있는 값을 접근하는 방식을 의미한다.
메모리에 객체를 올리고 내리는 작업을 수동으로 하다보니 다양한 문제들이 발생했는데,
기본적으로 발생하는 이슈가 바로 메모리 누수(Memory Leak)이다. '메모리가 샌다'고 표현을 하는데, 할당할 수 있는 메모리임에도 불구하고 메모리에서 내려지지 않은 다른 객체가 자리를 차지하고 있어 이도저도 못하는 메모리 공간이라 이렇게 표현하는 것 같다.
메모리 누수는 객체를 참조하고 있는 포인터가 사라졌음에도 해당 객체를 메모리에서 조금이라도 살려두게 된다면 일어나게 된다. 간단하게 정리하면 책을 빌려주는 도서관을 생각해보자. 책을 빌려주면 빌려줄 수록 빌릴 수 있는 책이 줄어든다. 이 도서관을 메모리라고 하고 책을 객체라고 본다면 줄어드는 공간을 볼 수 있겠다!
하지만 그렇다고 객체를 사전에 메모리에서 먼저 내리는 행위 또한 해결책은 아니라고 한다.
double-free라고 불리는 이 현상은 메모리가 작동하는 원리에 따라서 발생하는 문제라고 한다.
객체 A가 있다고 보자. 메모리 누수가 걱정되어 사전에 객체를 내리게 되면
이제 개발자와 컴퓨터는 객체 A가 있던 메모리 위치에 어떠한 데이터가 담길지 예측하지 못하게 된다.
컴퓨터는 순차적으로 메모리를 저장하지 않기에 발생하는 문제인 셈이다.
따라서 이 상황에서 객체를 다시 한번 메모리에서 내린다면 double-free가 발생한다.
처음 객체 A를 메모리에서 내리고 난 뒤, 다시 한번 호출되는 deallocation 덕분에 객체 A가 위치했던 메모리 공간에 새로 들어온 데이터를 변경(corrupt) 시키게 될 것이다.
반대로 pointer를 그대로 둘 경우에도 문제가 발생한다고 한다.
이 상황은 객체 또는 데이터가 메모리에서 내려갔지만 포인터가 존재하는 경우 발생하는 문제라고 한다.
이미 내려진 데이터의 포인터를 통해 데이터를 참조하게 될 경우, 데이터는 이미 내려졌기에 nil 또는 완전히 다른 데이터를 가져오게 되는 문제라고 한다.
어릴때는 주기억장치가 램인 이유가 이해가 안됐습니다
데이터 저장은 다 hdd에 하는데 왜 얘는 보조기억장치인지 의문이였죠
컴퓨터가 작동하려면 이론상으로는 램만 있어도 되기 때문에 그렇더라고요
Objc가 처음에는 MRC 였는데 ARC로 바뀐지 꽤나 됐습니다
처음에는 개발자에게 메모리를 관리할 책임을 크게 지웠는데 잘 안되었던건지 귀찮았던건지 요즘 새로 나오는 언어는 메모리 공간을 알아서 관리해주죠
RAM은 Random Access Memory의 약자인데 왜 이런 이름이 붙었을까요?
Cpu랑 메모리는 어떻게 정보를 주고 받을까요?
관심 있으시면 한번 찾아보시는 것도 좋을 것 같습니다