힙과 스택의 개념은?

ssk의 이미지

C언어로 프로그래밍시 힙이네 스택이네 하는 얘기를 종종 들어 왔는데 이게 무엇을 말하는지, 그리고 C언어로 프로그래밍시 언제 힙을 사용해야 하고 언제 스택을 사용해야 하는지 좀 알려주실 수 있을까요. (제가 질문을 제대로 하고 있는지도 잘 모르겠네요. :wink: )

힙과 스택에 대한 아무런 이야기라도 좋습니다. 워낙에 이야기만 많이 들었는데 책에는 잘 안나오더라고요. (물론 제가 공부를 덜한 탓이 가장 크겠지만.... :oops: )

감사합니다....

febace의 이미지

메모리에 힘과 스택의 영역이 존재 합니다.
힙은 malloc계열의 함수를 이용할때 사용하게 되고요
스택은 함수의 변수 및 콜 등을 이용할때 사용하게 됩니다.

기본적으로 (다른 스택, 힙 라이브러리를 만들어서 쓰지 않으신다면요)
오에스가 알아서 스택과 힙을 사용하게 해준다고 할수 있을것 같습니다.

힙은 프로세스가 존재 하는한 지속되는 성격이 있고요
스택은 함수호출 동안에만 존재 한다고 볼수도 있겠네요.

--- 무식이 탄로날까 걱정이지만 ~~ 도망 갑니다 ~

arimae의 이미지

W.Richard Stevens 씨께서 저술한 Advanced Programming in the Unix Environment 의 7.6절은 보면 C 프로그램의 Layout에 대해 설명이 나와있습니다.

간단히 설명해 보면

/-------------------------/  메모리상에서
|                         |       높은 구역
|         Stack           |
|                         |
/-------------------------/
|                         |
|          Heap           |
|                         |
/-------------------------/
|   Uninitialized data    |
| ---------Data---------- |
|    Initialized data     | 
/-------------------------/
|                         |
|          Text           | 
|                         |  메모리상에서
/-------------------------/       낮은 구역

Text segment : CPU에 의해 실행되는 머신 코드들이 있는 영역.Read Only

Initalized data segment : data segment 라 불리는 영역이며, 초기화된 외부 변수 static 변수등이 저장되는 영역입니다. 보통 Text segment + initialized data 영역을 합쳐서 프로그램이라고 합니다.
예) static int a = 1;

Uninitalized data segment : bss segment 라고 불리며, 이 영역을 프로그램이 실행될때 0 이나 NULL Pointer로 초기화 됩니다.
예) static int a; (외부 변수나, static 변수중 초기화 되지 않은 변수들)

Stack : 자동 변수들이 저장되는 곳이고, 함수가 호출될때 함수 안의 자동변수(함수내 로컬 변수) 등이 저장되는 곳입니다. 함수가 실행되는 동안에만 존재하며 함수의 실행이 종료되면 그 변수들도 사라집니다. 함수내의 자동 변수외에 saved frame pointer 등의 함수를 호출한 caller의 환경 정보도 저장합니다.

Heap : 동적 메모리 할당을 할경우 Heap 영역에 할당이 됩니다. Heap 영역은 uninitialzed data 영역의 top 과 stack 영역의 bottom 부분에 위치합니다.

이 밖에 더 자세한 것을 알고 싶으시면 Phrack 문서의 Smashing The Stack For Fun And Profit 을 읽어 보시거나 위에서 제가 언급한 책을 읽어 보시길 바랍니다. Phrack 문서는 해킹 문서로 해킹을 하기 전초 단계로 위의 영역에 대해 설명이 자세히 나와있습니다.

www.phrack.org 에서 받을 수 있으며, 49호 14 장이 위의 주제를 다룹니다.

Dream, Passion and Challenge..

고도리의 이미지

실제로는 물리적(혹은 논리적)인 메모리의 한 종류일 뿐입니다.

가장 큰 차이는 stack은 LIFO의 형태입니다. Heap은 위의 분의 프로세스
설명대로 그냥 메모리 공간입니다.

근데 왜 stack이랑 heap의 차이를 두느냐, stack은 주로 작업할때
데이터를 임시 저장하는 용도로 사용합니다.

여기에 LIFO라는 얘기가 나오게 되겠지요...

가장 간단한 예로 함수 호출을 생각해 보면, 함수를 호출하면 일단
현재 상태의 레지스터값을 저장해야하고, 함수를 호출할때 인자등을 건네
줘야합니다.

그것을 stack에 저장을 합니다. 그런 후 호출된 함수의 context쪽으로 들어
가겠지요... 여기서도 임시 저장공간으로 스택을 사용합니다.

그리고 계산을 다 한후 원래의 함수로 리턴을 해야하는데, 여기서 스택의
사용용도를 알 수가 있습니다.

일단 호출된 함수에서 사용한 값들은 다 사용을 했으니 리턴값을 빼고는 다
필요없으니 다 뽑아버리고요...

호출한 함수로 돌아가야 되니 함수호출하기 전에 저장했던 놈들을 다시
뽑아내야 되겠지요...

그래서 LIFO의 형태가 되야 하는 겁니다.

원래 컴파일러마다 함수호출관행이라는 것이 있는데, 자세한 것은
GCC manual의 해당부분을 보면 stack의 용도를 볼 수 있을 겁니다...

그럼...

서명.....음, 서명이라...

아싸!!! Three Go!

eagle123의 이미지

글을 읽다가 의문이 생겼는데요

스택과 힙의 크기는 얼마인가요? 고정크기가 있는지 아니면 가변적인 한계안에 크기가 있는지 궁금하네요. :?:

phenix96의 이미지

도스의 경우 다양한 메모리 모델이 존재하고 그 메모리 모델에 따라 스택과 힙의 크기가 달라집니다. 도스의 경우만이 아니고 다른 OS도 비슷하지요... :roll:

arimae의 이미지

윈도우 프로그램의 경우 기본적으로 Stack과 Heap의 크기의 Max 값은 1Mb 입니다. 그리고 전체 어드레싱이 가능한 주소는 4 byte 포인터 이므로 2 의 32승. 즉 4GB 의 메모리를 어드레싱이 가능합니다.
(kernel 2.4.0 에서는 이것을 4~64Gb 까지 확장했다고 합니다.)

http://kldp.org/KoreanDoc/Ulimit-KLDP
위 문서를 보면 리눅스의 경우 기본적으로 Max Stack Size는 8Mb 라고 하는군요.

참고하시라고 적어봤습니다.

Dream, Passion and Challenge..

eungkyu의 이미지

eagle123 wrote:
글을 읽다가 의문이 생겼는데요

스택과 힙의 크기는 얼마인가요? 고정크기가 있는지 아니면 가변적인 한계안에 크기가 있는지 궁금하네요. :?:

각종 주소를 출력하는 프로그램을 만들어보았습니다.

리눅스는 4G의 가상메모리중 1G정도는 메모리 직접 접근을 위해 특별히 사용하고, 3G를 사용자 프로그램이 사용할 수 있도록 제공한다고 알 고 있습니다.

/proc/pid/maps 을 출력한 것과 비교해보시면 대충 알 수 있을 겁니다.

#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

extern char **environ;

const int const_data = 0;
int init_data = 0;
int uninit_data;

void printfile(const char *filename)
{
        FILE *fp = fopen(filename, "r");
        char ch;

        if (!fp) return;
        while ((ch = getc(fp)) != EOF) {
                putchar(ch);
        }
        fclose(fp);
}

void printmap()
{
        pid_t pid = getpid();
        char *ptr;

        asprintf(&ptr, "/proc/%d/maps", pid);
        putchar('\n');
        printfile(ptr);
        free(ptr);
}

int main(int argc, char **argv)
{
        const int const_data_in_main = 0;
        int stack_data;
        static int static_data;

        void *heap_data = malloc(0);

        printf(
                        "%08x: printfile\n"
                        "%08x: printmap\n"
                        "%08x: main\n"
                        "%08x: &const_data\n"
                        "\n"
                        "%08x: &init_data\n"
                        "%08x: &environ\n"
                        "%08x: &static_data\n"
                        "%08x: &uninit_data\n"
                        "%08x: heap_data\n"
                        "\n"
                        "%08x: strerror(0)\n"
                        "\n"
                        "%08x: &stack_data\n"
                        "%08x: &const_data_in_main\n"
                        "%08x: &argc\n"
                        "%08x: &argv\n"
                        "%08x: argv\n"
                        "%08x: environ\n",
                        printmap,
                        main,
                        &const_data,

                        &init_data,
                        &environ,
                        &static_data,
                        &uninit_data,
                        heap_data,

                        strerror(0),

                        &stack_data,
                        &const_data_in_main,
                        &argc,
                        &argv,
                        argv,
                        environ);

        printmap();
        exit(0);
}
etourist의 이미지

우선 결론을 말하자면 힙이나 스택은 고정된 크기는 아닙니다.

늘어납니다. 하지만 한계가 있습니다.

프로세스들이 사용하는 메모리영역들은 4GB 크기의 선형주소 공간에서 유래합니다. 여기에서 필요한 영역을 받아서 사용하는 방식이죠.

1. 스택

스택에 push를 하다가 스택 메모리 영역을 삐져나가게-_- 되면 Page Fault 인터럽트가 발생합니다. 이 인터럽트를 핸들링하는 do_page_fault()에는 다음과 같은 코드가 있습니다.

if (error_code & 4 && address + 32 < regs->esp)
    goto bad_area;
goto good_area;

즉 스택포인터가 가리키는 부분을 초과해서 push한 이유로 생긴 페이지 폴트는 good_area 레이블로 이동하여 페이지를 할당받게 됩니다.

2. 힙

brk 시스템 콜은 힙의 크기를 변경합니다. malloc() 과 같은 POSIX API는 brk와 mmap() 을 이용하여 구현합니다. brk 시스템 콜은 페이지 단위로 메모리를 할당해서 프로세스의 메모리 영역에 추가합니다.

자세한건 리눅스 커널 코드를 참고하세요~ :wink:

[url]http://ldk.sarang.net [/url]
"꿈이 있는 자는 흔들리지 않는다! "

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.