본문 바로가기
개발 노트/기초 지식

[java] 메모리 영역

by tokkiC 2022. 4. 30.

컴퓨터의 메모리 영역은 유저가 사용가능한 유저영역과

유저가 손대지 못하는 운영체제 쪽 부분인 커널영역으로 나누어져 있다

컴퓨터를 할때 우리가 이런 저런 프로그램을 사용하지만 사용하며 컴퓨터의 기본 필수 시스템을 건드리면

컴퓨터가 에러를 일으키고 고장나게 될 수 있으므로

컴퓨터 실행의 중요한 부분 (운영체제) 등을 따로 분리해 놓은 것이다

이 중 유저 영역은 4가지 영역으로 나뉜다

code 영역, data 영역, stack 영역, heap 영역 이다

아래에서 위의 4가지 영역들을 간단히 설명하겠다


code 영역


말그대로 텍스트인 코드를 저장하는 영역이다
변수들을 어떻게 사용할지에 대한 프로그램 명령들을 여기에 저장한다


data 영역 (내부에 bss 영역 포함)


전역 변수와 정적 변수가 저장되는 영역이다
프로그램 시작 시 프로그램 종료까지 계속 메모리에 남아있으므로 전역 변수 사용을 최소화해야 한다

전역 변수 : 클래스 전체에서 사용가능한 변수

정적 변수 : static 이 붙은 변수, static 이 붙으면 그 자체로 객체화 되어 추후 변수 호출 시 따로 객체화 시키지 않아도 된다

data 영역에서 초기화를 시키지 않고(= "=" 을 통해서 값을 넣지 않고) 선언만 한 변수는
data 영역 내 부분인 bss 영역에 저장한다.

어차피 0으로 초기화할 변수들이라면 한 곳에 몰아두고 그 영역 (bss영역) 전체를 0으로 만드는 게 편하기 때문이다


stack 영역


메소드 내의 지역 변수, 매개변수(인자를 값으로 가지는 변수)를 저장하는 영역이다
데이터를 저장하는 push 와 데이터를 꺼내는(값을 가져오는)하는 pop 의 형태로 동작한다
LIFO (Last In First Out 마지막에 넣은게 먼저 나옴) 구조를 가진다
stack 은 쌓아올린다는 뜻인데 예시로 설명하자면 아래 그림과 같다

변수에 여러번 값이 할당 시 할당되는 값들을 쌓아 올려서 마지막에 할당한 값을 빼내는(가지게 되는) 방식이다

사실상 변수값 할당 시 이전 변수값은 버리고 새 값으로 덮어쓰게 된다는 내용이다
참조값을 가지는 변수의 경우, stack 에 주소값만 저장하고 주소값으로 heap 의 주소를 가르켜 값을 가져오게 된다


heap 영역


stack에서 참조하는(가리키는) 값을 저장하는 영역이다
stack 영역에서 참조하는 객체(인스턴스), 메소드, 배열, 문자열 등등이 해당된다
stack 에서 값을 바로 갖지 않고 주소를 할당해서 참조하기 위해 사용되는 영역이다
사용자가 값을 관리하는 영역이라고 할수있다

이미지 출처 : https://www.hackerschool.org/Sub_Html/HS_University/BOF/essential/PDF_Files/15.pdf

메모리의 총 구조는 위와 같다

stack 영역의 바닥은 커널 구조와 맞닿아있고 커널과 반대방향이므로
stack 에 데이터가 추가 될수록 주소값이 낮은 방향으로 데이터가 쌓이게 된다
(stack 의 커널 영역과 맞닿은 초기 주소값을 bottom 이라 하고 커널 영역 반대 방향으로 데이터를 쌓아서
생긴 스택영역의 끝이자 가장 최신에 저장된 주소값을 top 이라고 한다.
주소값은 bottom 이 가장 높고 stack이 쌓일수록 낮게 할당하니 top은 가장 낮은 주소값이다

heap 영역의 경우 data 영역에 닿아서 메모리의 낮은 주소값부터 높은 주소값 순으로 데이터를 저장하게 되는데
heap 과 stack 사이의 빈 주소값 영역을 공유 라이브러리 영역(Shared Library)이라고 하며
공유 라이브러리 영역이 없이 heap 과 stack의 끝이 닿아버리면 에러가 생기는데

stack 이 heap 을 넘어 침범하는 경우를 스택 오버플로우 Stack Overflow (잘못된 재귀함수 사용 시 생긴다고한다)
heap 이 stack 을 넘어 침범하는 경우를 힙 오버플로우 Heap Overflow 라고 한다

재귀함수 : 스스로를 호출하여 반복실행하는 함수

댓글