[c++] Stack 메모리와 Heap메모리에 관한 질문 (함수주소출력예
글쓴이: gyxor / 작성시간: 목, 2003/10/09 - 9:40오전
#include<iostream> using namespace std; void ee() // static 으로 선언 했을경우와 주소값이 다릅니다. { cout << endl << ee; } int main() { ee(); return 0; } #include using namespace std; static void ee() { cout << endl << ee; } int main() { ee(); return 0; }
그런데.. 일반함수나 static함수나 차이가 있는것인가요?
함수이름자체를 출력해봤을때 주소값이 바뀌는것을 볼수가
있는데요..
그것은 왜 그런것인지 모르겠습니다.
메모리의 종류(사용분야)가 다르기 때문인가요?
stack과 hip메모리는 전혀 다른 공간인가요?
답변부탁드립니다.
Forums:
클래스 멤버가아닌 전역 함수에 static이 붙는, 이른바 전통적인 C
클래스 멤버가아닌 전역 함수에 static이 붙는, 이른바 전통적인 C 에 기원을 둔 static 은 단지 scope 제한 만을 문법적으로 정의한 것입니다.
구현상으로는, export symbol table에 들어가느냐 들어가지 않느냐의 차이가 생기게 되며, 따라서 외부에서 link 가능한 함수이냐아니냐의차이일 뿐입니다.
주소값이 달라지는 것은 큰 의미가 없습니다.
함수는 stack아니 heap 등에 위치하는 것이 아니기 때문이지요.
p.s. 제 컴파일러는 gcc/g++ 2.96 (redhat)인데 달라지지 않습니다.
---
http://coolengineer.com
스택과 힙은 운영체제쪽에서 좀더 자세하게 다룹니다.
스택은 어떤 특정 시점 t1 에서 함수나 다른 프로세스로 컨텍스트 스위칭이 되면 기존에 작업하던 일감을 저장하기 위해서 사용하게 되죠. 이 부분이 심히 부족하게 만드는 경우(보통 recursive func에서 많이 발생)에는 SEGV(segmentation violation)을 유발하여 프로그램을 죽이기도 하죠. 따라서 프로그래머는 개발시 항상 이 영역을 생각해두고 개발해주는 것도 중요하죠. 무작정 스택을 소모하는 프로그램을 짜는 것은 좋지 않습니다.
힙은 가상메모리 영역에서 끌어다 쓰는 시스템에서 빌려주는 자원메모리라고 생각하시면 됩니다. 주로 paging을 통해서 입출력되는 메모리가 바로 힙메모리입니다. 이게 부족하게 되면 시스템이 전혀 작동이 안되어버리죠. 단순한 프로그램문제가 아니라 운영체제를 맛가게 할 수도 있습니다.
PS) Hip이 아니라 heap입니다. ^^
========================================
* The truth will set you free.
좋은 답변감사합니다.
위 내용이 잘 이해가 되지 않습니다.
아래의 내용은 다른사이트에서 어느분이 해주신 답변입니다.
내용에서 처럼 메모리를 free영역을 제외하고 3가지만 생각했을때
프로그램이 실행이 되면
코드영역에는 순수한 소스내용만 들어가고
heap영역과 stack 영역에 나눠서 변수및 함수가 들어가는것이
아닌가요?
실제로 구현을 해봤습니다.
다소 방대하지만..
중요한 요점은..
위의 글처럼..
일반함수와 지역변수는 stack에 들어가므로.. 주소값이 감소하고
전역변수,static함수및 변수는 heap영역에 들어가므로 주소값이 증가를 합니다
함수의 경우에 주소값이 일정하게 늘어나거나 증가하지는 않았습니다.
일반함수는 감소하고
static함수는 증가한다는것은 알 수 있었습니다.
그런데..
pynoos님께서 함수주소가 gcc에서 같다고 하셨기 때문에 vc6.0에서만
해본 저로서는 좀 헷갈립니다.
첫째, 왜 그런것인지..잘 이해가 안됩니다. 컴파일러마다 이런부분마저도
다를수가 있는것인가요?
위 내용에서 틀린부분이 있다면 알려주시면 감사하겠습니다.
둘째, 이것은 위 내용에서 좀 확대되는 질문이지만..
recusion을 많이 하게 되면 stack overflow로 에러가 나는데요..
c++기초플러스에서도 그렇고.. 교수님도 그렇고.. 메모리 heap을
늘려주면 좀 낫다고 하셨는데요.. vc6.0메뉴에서 heap을 늘려주는
부분이 있다고 하는데요.. 왜 stack이 아니라 heap인지
모르겠습니다. 'stack을 늘려라' 라고 해야되는것 아닌가요?
c에서는 재귀호출을 heap을 사용해서 하는것인가요?
heap 을 이용한 재귀호출구현이 가능한가요?
제가 알기로 heap메모리는 랜덤하게 비는곳이 값을 넣은것으로
알고있습니다.
두가지 답변부탁드립니다.
참고삼아 말하자면, Code영역, Data영역이라던가 Stack영역, h
참고삼아 말하자면, Code영역, Data영역이라던가 Stack영역, heap영역 같은 구분은 특정 컴파일러(혹은 대다수의 컴파일러?)에나 해당하는 얘기입니다. 원래의 C/C++에는 그런 개념은 포함되어 있지 않으며, 단지 기억 수명(storage duration)과 통용범위(scope)라는 개념이 있을 뿐입니다.
개인적으로, 어떤 객체가 Stack영역에 저장되느냐 heap 영역에 저장되느냐 하는 것은 크게 중요한 사항은 아니라고 생각합니다. 그런 것들은 구현체가 알아서 할 일이고, 프로그래머는 단지 기억수명과 통용범위에 대한 것들만 알아두면 충분하다고 생각합니다.
물론 뭐든지 알아서 나쁠 것이 있겠습니까마는, 어떤 방식으로 설명하는게 낫냐고 한다면 저는 Stack이나 heap 등으로 설명하기보다는 기억수명과 통용범위란 개념으로 설명하는 쪽을 택하겠습니다.
Code영역이라는 것을 알경우 유용한 경우도 있지요.[code:1
Code영역이라는 것을 알경우 유용한 경우도 있지요.
이런 코딩을 하면 Segmentation fault가 일어난다는 것을,
큰따옴표로 구분된 문자열은 Code영역에 위치하기 때문에
read only 속성인데 쓰기를 했으므로 그렇다.. 라고 설명이
가능하지 않은가요?
진리를 나의 수준으로 끌어내리지 마라.
나를 진리의 수준으로 끌어올려라. - 배꼽 중에서
Re: 좋은 답변감사합니다.
순수한 소스와 코드라는 두가지 용어를 사용하셨는데, 만약 순수한 소스가 C 원본이라면, 잘못이해하신 것같습니다. 소스는 컴파일되면 더이상 실행 파일에 있지 않습니다. heap 영역과 스택은 컴파일되어 나온 파일안에는 없고, 실행되면서 잡히는 것입니다.
대게 실행파일이 로드되어 메모리가 잡히면, 데이터 영역의 뒷부분에 이어서 잡힙니다. 함수 즉 텍스트라고도하는 부분은 코드영역이 따로 있어 거기에 들어갑니다.
뭔가 많이 잘못된 듯한... :(
exe 파일에는 함수(extern static 모두), 전역변수, 정적변수 모두 들어갑니다.
데이터 영역은 크게 둘로 나뉩니다. data와 bss 이지요. 더 세분하면, data도 readonly 와 read/write 까지도 나누기도 합니다.
data에는 초기값이 있는 변수가 들어가며, 여기에는 문자열도 포함됩니다. bss에는 초기값이 없는 즉, 암시적으로 0으로 채워지는 변수들이 들어갑니다.
테스트 코드에서 함수 주소가 바뀐다고해서, stack이니 heap이니 나누는것은 옳지 않습니다. 컴파일되고 난뒤 배치가 그러할 뿐입니다.
두번째 질문에는 recursion이 만약 무한이라면, 무한의 stack이 필요하겠습니만, 다소 깊은 recursion이라면, 기본적으로 호출을 위해서는 stack을 늘여야하며, 만약 recursion되는 함수에서 계속 heap 할당을 한다면, heap도 늘여야하겠지요.
---
http://coolengineer.com
[quote="dondek"]Code영역이라는 것을 알경우 유용한 경우도
현재 표준 문서가 없어서 확인이 불가능한데... 아마 C 표준에 String literal을 변경하는 행동은 아예 금지되어 있거나 undefined behavior를 갖는다고 쓰여있을 겁니다. (아마도 undefined behavior쪽이겠지만... 문서가 없으니-_-;;)
물론 특정 C 구현체가 내부적으로 어떻게 구현되었는지를 알고 있으면 실질적인 문제 해결을 할 때 유용한 경우도 있습니다. 그러나 님께서 드신 예는 일반적인 개념으로 충분히 설명 가능하기 때문에 그런 상황에 해당하지 않습니다.
Re: 좋은 답변감사합니다.
재귀호출시 heap과 stack에 관한 내용은 정말 감사합니다. ^^
잘 알겠습니다.
물론 exe파일에는 (프로그램을 실행할수 있는 내용)기계어로 다 들어가 있겠지만요..
제가 말씀드린 내용은.. 프로그램이 실행되는때(런타임)
에 메모리 상의 내용입니다. 어짜피 프로그램이 실행이 되려면 exe파일의
내용이 하드에서 메모리로 불려오는것 아닌가요?
그때의
메모리를 나눴을때 코드영역,stack영역,heap영역에 대해서 말씀드린것입니다.
컴파일러마다 차이가 있는것은 이해하겠지만
위 내용이 좀 이해가 안되서요..
정확히는 컴파일러만 관계있는것이 아니라, OS의 application b
정확히는 컴파일러만 관계있는것이 아니라, OS의 application binary interface에서 정의하는 것입니다.
application은 이러이러한 구조로 되어야한다. 는 것이지요.
함수는 stack, heap에 들어가는 것이 아닙니다.
따라서, 함수가 어떤식으로 발견된다고 하여서 그것이 그런 메모리 운용방식에 맞는 곳에 위치하는 것이 아닙니다.
---
http://coolengineer.com
[quote="dondek"]Code영역이라는 것을 알경우 유용한 경우도
Code 영역이 아니라 data 영역에 잡히는 것입니다. 위에서도 언급하였지만, data 영역은 writable과 readonly가 따로 있습니다. 물론 없는 architecture도 있습니다. 하지만, 위의 예제에서 seg fault가 난것을 보면, 구분이 되어 있는 (요즘의 linux 같은) machine에서의 예제입니다.
컴파일러는 이것과 관련된 재밌는 option이 있습니다. string literal을 과연 어떤 data 영역에 둘것인가지요.
다음 코드를 살펴보시면, 위 코드를..
위의 코드를 다음과 같이 b1, b2로 만듭니다. 옵션은 -fwritable-strings 입니다.
그리고, 각각의 section중에 data 영역을 dump 해보면... b2에는 존재하지만, b1에는 존재하지 않습니다.
readonly data 영역을 dump 해보면, b1에 만 존재합니다.
info objdump
~~
즐거운 메모리 해킹되시길.. 바랍니다..
---
http://coolengineer.com
감사합니다.
제가 한가지를 잘못알았었군요..
여러번해보니..
사실 이소스에서 함수의 위치값은 랜덤했습니다.
그리고 랜덤한것이 이해가 됩니다.
일반함수가 스택메모리에 위치한다고 말씀드렸던것은 제가 틀렸습니다.
스택에 들어가는것은..
어셈에서만 봐도.. 함수호출 리턴후
그다음에 실행될 Instruction Pointer 값이 들어가게
되는데요..
그것을 함수의 내용 자체가 스택에 들어가는것으로 착각을 했습니다.
죄송합니다.
그런데..
실제 함수의 주소를 출력했을때의 그 주소값..
그 주소값이니까 메모리상의 어딘가일텐데요 분명..
첫째, 즉, 함수가 위치한 곳은
메모리에서 exe파일을 불러온 메모리상의 위치가 되는것인가요?
아니라면 어디가 되는지 궁금합니다.
둘째, 일반함수를 제외한 나머지
static함수,전역변수,static변수의 주소도 마찬가지로 메모리상의 어느 공간의
주소인가요?
물론 메모리상의 어디에 위치하는가가 별로 중요하지 않을수도 있지만요..
말씀드린대로 메모리에도 구역이 있고 변수나 함수의 종류마다 위치되는
곳이 정해져있을거 같아서요..
그것이 궁금합니다.
두가지..
답변부탁드립니다.
맞습니다. 메모리에 적재되고 적당한 재배치를 한 주소값입니다.
맞습니다. 메모리에 적재되고 적당한 재배치를 한 주소값입니다.
static 과 상관없이 함수는 code (text) segment에 변수는 data,bss segment에 잡힙니다.
여기에서 변수는 자동변수를 제외한 전역변수와 함수내 static 변수를 따졌을때,
이 함수가 export 되느냐 안되느냐에 따라 다른 모듈과 링크될것인지 말것인지를 나타낼뿐입니다.
Windows를 사용하신다면, DUMPBIN을 사용해보세요.
---
http://coolengineer.com
어셈블리어에서 배운대로군요..메모리의 세가지 code segmen
어셈블리어에서 배운대로군요..
메모리의 세가지
code segment 명령어(실행코드) 함수(???)
data segment 변수,상수
stack segment 함수호출시 사용
제가 처음에 인용했던 내용에서도 이 세가지를 가지고 얘기를 했던거 같군요..
data부분에 static변수와 static함수와 전역변수가 들어간다고 한것을
제가 heap에 들어가는것으로 이해를 잘못했습니다.
자료구조 책에서
|코드|스택|free영역|힙| 이렇게 그림으로 표현된..
이런식으로 메모리를 구분한것을 보고.. 제가좀 착각을 했는데요..
힙은 데이터영역의 일부였군요..
stack에 일반함수가 들어간다고 했던것은 좀 어폐가 있지만
의미상으로 일반함수 호출시에 쓰인다고 이해하면 되겠죠?
위 내용대로라면 거의다 이해가 되는데요..
마지막으로 네가지 물음이 생기는데요..
그렇다면
첫째,
위 메모리구조대로라면..
heap메모리는 위 메모리외에 추가로 할당되는것인가요?
어디에 쓰이는것인가요? 동적할당에만 쓰이나요?
둘째,
중간에 테스트한대로라면..
분명히
static변수와 전역변수(^^)는 주소값이 4씩 늘어났지만
로컬변수의 경우엔 4씩 줄어들었습니다.
이것이 이해가 안됩니다.
이러한 현상은 어떻게 설명이 되는지 궁금합니다.
main함수내의 지역변수를 출력할때에 이미 main함수가 호출된 상태이고
그래서 주소값을 출력했을때에는 로컬변수가 stack에 위치한주소대로
출력이 되기 때문이라고 생각하면 되나요?
셋째, 함수가 code segment내에 들어갈때에는 함수내의 지역변수는
어떤식으로 저장이 되나요?
data segment 내에 변수가 저장이 되듯이 들어가나요?
만약
void show()
{
int i=0;
cout << i;
}
이런함수라고 예를 들었을때요..
네번째,
또한 만약 두번째와 세번째 질문이
제가 생각한것이 맞다면.. 지역변수의 주소를 main함수에서
출력을 했을때에 code segment내의 변수주소가 아닌 stack내의 변수의
주소를 출력하는 이유는 무엇인가요?
뭔가 또 잘못 이해된거같은 기분입니다만..^^:
네가지 답변부탁드립니다.
로컬변수의 경우엔 4씩 줄어들었습니다. 3개의 int 지역변수를 선언
로컬변수의 경우엔 4씩 줄어들었습니다.
3개의 int 지역변수를 선언했을때
스택의 높은 번지에서부터 입력되기때문에
하나씩 들어가면.... 주소는 작아집니다.
data1 | ffff
data2 | .
data3 | .
____ | .
____ | 0
(함수밖의 지역변수는 없는것 같은데) 지역변수는 스택에 들어갑니다.
code segment에는 지역변수저장공간을 마련하지 않습니다.
함수가 호출되면 스택에 저장할 공간을 마련합니다.
어셈블러로 보면 여기에 해당하겠죠
subl $12, %esp
추가적으로 한마디하자면 코드세그먼트에서 스택에 접근할때는
esp의 상대 위치로 (물론 계산결과는 스택번지겠죠) 이용합니다.
그나저나 백수 언제 탈출하냐... ㅡㅡ; 배고파라.
[quote="gyxor"]첫째,위 메모리구조대로라면..hea
추가로 할당되는 것이고 동적할당에만 쓰입니다.
Kernel에 data segment를 증가시켜달라고 (brk 명령)요청하고, 증가되는 양을 heap으로 사용합니다.
지역변수와 로컬변수가 ?? 잘못 쓰신듯.
전역변수 이거나 함수안의 static 변수는 당연 스택에 안잡히므로 늘어 나겠지요.
로컬변수 즉 자동변수는 실행중에 만들어지며 스택에 생기므로 줄어 들겠지요.
함수에 붙은 static 에 의해 함수 포인터가 값이 처리되는 방식이 달라지는 것은 저도 모르겠습니다.
(컴파일러가기분 내키는대로? ^^)
지역 자동변수의 경우 data sement에 생기는 것이 아니라 stack에 생기며 단지 스택포인터를 감소시키는 것으로 메모리를 할당합니다.
아주 값싼 할당방법이죠. 커널에 요청하는 것도 아니고, compile time 때 심볼을 가지고 data segment한자리 차지하는것도 아니고....
아마 네번째질문은 잘못이해하시고 있기때문에 한 질문이라 생각되므로.. 여기까지... :)
---
http://coolengineer.com
답변감사합니다.
함수의 지역변수가 stack segment에 들어간다면..
앞에서 말씀하신 내용중에서
code segment 내에 함수() 가 들어간다는것은..
함수내의 지역변수를 얘기하는것이 아니라..
프로그램 실행시에 함수를 호출하는 명령과 그때의 함수안의 변수나 명령어
등에 관한 정보를 code segment가 가지고 있고.. 그걸 바탕으로
지역변수의 공간은 stack에 자리를 잡게 된다고 이해하면 되나요?
답변부탁드립니다.
옳습니다.
옳습니다.
---
http://coolengineer.com
쩝 내용이...
보니까 기계에 의존적인 부분이 많네요
위의 질문하신 내용은 , 기계마다 차이를 가질수 있는 내용이므로
중요한게 아닌거 같습니다
추상적으로 이해하고 있는부분을 컴파일러가 어떻게 구현했냐는 차이겠죠
주소가 올라가서 혹은 내려가서 스택에 할당됐냐? 절대 아닙니다
기계마다 컴파일러마다 방법이 다 틀립니다
그리고 힙 메모리는 윈도우 일 경우 잘 기억은 나지 않지만
프로세스에 디폴트로 1메가를 잡습니다
하지만 1메가보다 커질 경우 OS가 자동으로 힙 크기를 늘려주는 작업을하게
됩니다 , 그냥 할당했을때 보다 시간이 좀더 걸리겠죠
참고로 유닉스의 내부라는 책의 커널 메모리 부분을 보시면
힙 메모리를 어떻게 관리하는지 보실수 있습니다
예를 들면 31바이트 메모리 할당을 요청하면 2의 멱수 단위로
끊어 놓은 리스트들을 돌며 ,31바이트와 제일 비슷한 32 바이트메모리를 가져올수있는지 리스트를 체크합니다
있으면 그 리스트에서 메모리를 가져다가 할당해 줍니다
[없으면 64바이트에서 비었는지 확인하고 가져 오는 방식]
한마디로 기계에 종속되거나 컴파일러에게 종속된 부분 보단
추상화된 개념을 정확히 이해하는게 중요하지 않을까 싶네요?
승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스
저도 추상적인 이해가 중요하다고 생각합니다.
C언어는 인터프린터로도 충분히 만들수 있습니다. 표준은 그렇게 되어있구요.
heap이나 stack은 컴파일러 혹은 인터프린터, 운영체제, 하드웨어 어느 것에 의해서도 흔들릴수 있는 부분입니다.
저도 추상적인 이해가 중요하다고 생각합니다.
- 죠커's blog / HanIRC:#CN
학습과 인식에 대해 이야기하자면
저는 솔직히 실력이 많이 부족합니다.
이곳의 실력있는 분들께는 항상 고개가 숙여지죠.
이 주제에 대한 글들을 읽으며, 추상적인 이해가 중요하다는데에는 공감합니다만 사실 학습은 일반적인 이론에서부터 구체적인 실용으로 접근하는 것(흔히 하향식 접근(top-down approach)이라 하죠 )으로만으로는 불가능합니다.
물론 다들 아시는 소리지만 또한 구체적 실례학습에 대한 지지가 부족한 느낌이라 조금 딴지를 거는 건데요...
사실 표준이라는 것도 기술이 태동되고, 이것이 다양한 platform 에 적용되면서 그 필요성이 요구되고, 만들어집니다. 표준은 다양한 구체적 기술들을 감안하면서 일반화시키고, 앞으로의 기술들을 거시적 시점에서 좋은 방향으로 이끄는 것일겁니다.
이미 C, C++ 가 대중적이고, 표준이 확립된 시점에서 실력자들이 표준과 일반적 이론을 중시하는 것은 당연하지만 초보자들에게 그러한 것을 들이대면 도무지 감이 안 잡히는 것이죠.
여기에 있는 실력있는 분들도 게시하는 글을 보면 많은 예를 익히고, 시행착오를 거친 이후에 표준과 일반적 이론을 나름대로 통찰했을 거라고 봅니다.
힙,스택이 머신 종속적이라고 해도...
그 근본적인 개념이나 실행파일의 구조는 대부분 비슷합니다.
실제로 유닉스의 경우는 스택메모리를 제한시켜놓고 프로그래밍을 해서 recursive func 같은거에 스택을 소모시키게 하면 바로 뻗는 것을 볼 수 있습니다. 힙과 스택의 구조가 머신종속적이라는 것은 그것을 구현하는 방법일 뿐이지 위에서 말한 주소가 감소하거나 혹은 데이터가 저장되는 것의 차이는 거의 없습니다.
간단하게 프로그램을 짜서 돌려보면 쉽게 알 수 있습니다. 특히나 유닉스계열에서는 거의 비슷하게 작동하죠. 윈도우즈에서는 어떻게 스택을 제한을 거는지 몰라서 해보지는 못했습니다.
========================================
* The truth will set you free.
윈도우에서는.....
윈도우에서는 스텍을 디폴트로 1M를 잡습니다 [ 처음부터 다 잡는건 아니고
확정은 약 8k정도 하고 예약으로 1M가 잡는것입니다]
여기서 한번에 스텍에 1M가 훨씬 넘는 메모리를 할당한다면
바로 스텍오버 플로어가 나버리죠
하지만 1M선쯤에서 약 몇k 정도 메모리는 무슨 -_-; 상태를 걸어둡니다
따라서 스택에 1M가 조금 넘는 ? k 정도의 메모리에 접근을 하면
메모리 예외 상황이 발생하면서 윈도우가 스텍크기를 배로 늘려주는
작업을 해주게 됩니다
참고로 스택 크기나 힙 크기는 컴파일러에서 처음부터 조절이 가능합니다
승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스
pynoos님을 비롯해서 좋은 답변해주신 모든분들께 정말 감사드립니다.
pynoos님을 비롯해서 좋은 답변해주신 모든분들께 정말 감사드립니다. ^^
사견이지만...
개념이나 실행화일의 구조가 대부분 비슷하다는 것에는 동의하지만 recursive func에 견뎌내는 임플리멘테이션도 존재합니다. :-)
- 죠커's blog / HanIRC:#CN
댓글 달기