malloc 함수에 관하여

canuyes의 이미지

현재 후배들과 c 스터디 중에 있습니다.

저번 시간에 malloc 함수에 관하여 설명해주는데,

"저는 malloc 함수는 메모리의 할당만 책임지고, 초기화는 책임지지 않는다."

라는 내용을 주로하여 calloc과 비교하여 설명하였습니다.

그런데 한가지 질문이 나온것이,

"gcc 상에서 아무리 malloc을 실행해도 초기화된 결과를 얻는다." 라는 이야기였습니다.

실제로 수행해보니,

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 int main(void) {
  5     int *a = (int*)malloc(sizeof(int));
  6     printf("%d\n", *a);
  7     return 0;
  8 }

위와 같은 코드는 항상 출력이 '0' 으로 동일했습니다.

물론, 위의 코드에서 malloc 수행전에,
heap 영역에 내용을 썻다 지우면 (malloc 후 free) 0이 아닌 값이 나오는 경우도 있기는 했습니다.

그럼에도 불구하고 위와 같은 코드가 항상 0을 출력 결과로 내놓는 것이 매우 신기했습니다.

제 질문은,
프로그램에서 최초로 실행되는 malloc은 초기화된 결과를 얻을 수 있나요?
입니다.

의미 없는 질문이기는 하지만, 작동이 너무 궁금해서 질문드립니다.

kukyakya의 이미지

커널이 새 페이지를 할당할 때 0으로 초기화해줍니다. (http://stackoverflow.com/questions/6004816/kernel-zeroes-memory의 R..이 작성한 코멘트 참고)

main 함수가 호출되기 전의 startup code에 따라 다르겠지만 malloc과 free를 반복적으로 호출해서 사용하도록 구성되어 있지는 않을 것이므로 첫 malloc시에는 zero-initialize된 영역을 할당받을 확률이 높겠죠.

하지만 그렇다고 해서 malloc으로 할당받은 영역이 0으로 초기화되어있다고 가정하면 안됩니다.

익명 사용자의 이미지

저희 스터디에서는 x86_64 GNU/Linux 를 사용합니다.

스터디원이 겪은 것은 현재 사용하는 시스템에서만 가능한 것이며,

이전에 수행된 프로그램이 어떻게 구현되었나에 따라서 결과가 보장되지 않는다고 이해하면 되나요?
(이전에 다른 사람의 프로그램이 malloc free를 반복 사용한경우)

canuyes의 이미지

글쓴이 입니다!

참고로, 동일한 코드를 visual studio 로 수행하니 쓰레기 값이 나오네요!

jick의 이미지

일단 정답은 그냥 "절대 아무런 보장이 되지 않는다"입니다. 코드를 짤 때는 malloc으로 받은 영역에 뭐가 있을 거라고 전혀 가정해선 안되며 "어 이렇게 100번 돌렸는데 다 0이던데?" 같은 생각으로 프로그램을 짜다가는 마지막 순간에 고객 앞에서 (혹은 교수님 앞에서) 터지게 됩니다.

그건 그렇고,

"이전에 수행된 프로그램이 어떻게 구현되었나에 따라서"와는 상관없습니다. 요즘 쓰이는 거의 모든 OS는 (리눅스, 맥, 윈도우즈, 등등...) 프로세스 별로 메모리를 따로 관리하기 때문에 하나의 프로세스에서 내부적으로 사용한 메모리를 다른 프로세스에게 보여주지 않습니다. (만약 그렇지 않다면 엄청난 보안 문제가 되겠죠. 일반 사용자가 malloc했는데 그 메모리에 서버 관리자가 쓰던 패스워드가 그냥 들어있다든지...) 따라서 OS가 다른 프로세스에게 메모리를 할당해 주기 전에 반드시 초기화를 합니다. 십중팔구 0으로 초기화를 하겠죠.

하지만! 0으로 초기화를 한다는 게 보장되는 건 OS를 직접 불러서 mmap 등등을 할 때 보장이 되는 것이지, malloc을 불렀다면 malloc이 일단 OS에서 받은 메모리를 가지고 무슨 일을 한 다음에 메모리를 돌려줄지 알 수 없기 때문에 그 영역에 무슨 값이 있다는 것은 전혀 보장이 되지 않습니다.

klara의 이미지

0도 쓰레기값 중에 하나일 뿐입니다.
쓰레기값이 들어있다는게 랜덤한 값이 들어간다는 뜻이 아니라 그안에 어떤값이 들어있다고 가정해선 안된다는 뜻이죠.

표준에서 명시하지 않은 것에 의존하면 내컴퓨터에서는 백만천 천만번 성공했어도 다른데에서도 성공한다는걸 보장하지 않습니다.

canuyes의 이미지

그나저나 시스템이 zeroed assign 을 해준다는 건 정말 처음 듣네요..
malloc 은 system call 을 사용하지 않는 것으로 알았는데..

klara의 이미지

잘못이해하신거 같습니다.
malloc이 0으로 초기화하는게 아니라, (어쩌다보니) malloc이 가져온 곳이 0으로 초기화되어있는 곳이라는 뜻입니다.

kukyakya의 이미지

malloc 내부에서 힙 영역이 부족할 경우 brk()나 sbrk() 시스템콜을 통해 힙 영역을 증가시켜달라고 커널에 요청합니다.
요새 구현은 mmap() 시스템콜을 쓴다는것 같았는데 glibc 소스 코드를 확인해보시면 될 것 같아요.

그냥 아주 간단하게 'malloc(이나 new)을 통해 할당받은 메모리에는 어떤 값이 들어가 있을지 모른다'라는 원칙만 갖고 계시면 됩니다.

Necromancer의 이미지

몇년전에 malloc() 어떻게 구현했는지 살펴보았는데 glibc 매뉴얼에는 다음과 같이 써져 있었습니다.

1) 소량 메모리 요청일 경우는 brk(), sbrk()로 사용
- 프로세스의 메모리 끝점을 올리거나 내리는 식으로 할당/해제합니다.

2) 4K 이상 요청시는 mmap()으로 할당합니다.
mmap() 함수는 파일을 특정 메모리 영역에 매핑시키는 시스템콜인데 메모리 할당만 필요한 경우 리눅스는 MAP_ANONYMOUSE 옵션을 줘서 매핑시키고 다른 유닉스 계열의 경우 /dev/zero를 매핑시킨다고 하네요.

Written By the Black Knight of Destruction

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.