alloc계열 함수의 오버헤드???

xjiwoox의 이미지

1. 함수 내부의 변수(static 말고 stack상에 유지되는...)
char buffer1[100];
2. heap을 할당받는 변수
char *buffer2;
buffer2 = (char *)calloc(1, 100);
free(buffer2);

1,2번 모두 함수 수행시 똑같이 100바이트의 메모리를 쓰게 됩니다.
1번과 2번을 비교했을 때 2번이 확실히 손해가 많을 것 같습니다만...
어느정도나 차이가 날까요?

Necromancer의 이미지

당연히 heap이 오버헤드가 더 크고요.

heap의 구현 방식에 따라 차이가 날겁니다.
단순이 linked list 형태로 구현된 힙이라면 메모리상의 블럭수에 비례하는
시간이 걸리겠죠. tree 형태로 구현하면 더 적게 걸리긴 하지많요.
메모리도 heap 방식의 경우 블럭 정보를 기록하는데 추가로 몇바이트가
소요됩니다. (glibc에서는 한 16바이트인가 32바이트인가.... 그정도)

(저도 어셈블리로 malloc 몇번 구현해 본적이 있습니다. 리눅스상은 아니지만
보호모드 프로그램에서 메모리 할당 코드 만들면서... heap이라고 불리는
특수한 트리를 사용했죠.)

함수상에서 선언된 변수의 경우 스택 포인터에 덧셈이나 뺄셈을 해서 공간을
확보하면 끝납니다. 확보할 공간의 크기는 컴파일러가 컴파일할때 다 알아서
계산하죠.
함수내 변수의 단점은 해당 함수 내에서만 쓸 수 있다는 겁니다.

Written By the Black Knight of Destruction

mastercho의 이미지

힙이라는 구조는 자료구조책에 트리구조로 나오는데 -_-;

힙을 링크드 리스트로 구현하셨다는건 좀 .....

힙 자체는 엄연히 트리형태입니다

링크드 리스트로 구현 하셨다면 링크드 리스트 메모리가 아닐런지 ㅎㅎ
[원래는 자유 메모리라고 하죠? 트리구조의 힙 형태를 갇추었다고 해서
힙 메모리로 불리는걸로 알고 있습니다만은?]

2번 같은 경우
힙에서 빈 공간을 logN의 형태로 찾아야 하고

또한 멀티 쓰레드 일 경우 동기화까지 하기때문에.....

오버해드가 큰걸로 알고 있습니다

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

pynoos의 이미지

mastercho wrote:
힙이라는 구조는 자료구조책에 트리구조로 나오는데 -_-;

힙을 링크드 리스트로 구현하셨다는건 좀 .....

힙 자체는 엄연히 트리형태입니다

링크드 리스트로 구현 하셨다면 링크드 리스트 메모리가 아닐런지 ㅎㅎ
[원래는 자유 메모리라고 하죠? 트리구조의 힙 형태를 갇추었다고 해서
힙 메모리로 불리는걸로 알고 있습니다만은?]

자료구조에서나오는 heap과 메모리 종류로서의 heap은 사실.. 거리가 좀 있는 개념이라,

메모리에서의 heap이 구현방식이 b-tree 이거나 linked list 로 될 수 있다는 말은 옳습니다.

Quote:
1,2번 모두 함수 수행시 똑같이 100바이트의 메모리를 쓰게 됩니다.
1번과 2번을 비교했을 때 2번이 확실히 손해가 많을 것 같습니다만...
어느정도나 차이가 날까요?

이루 말할 수 없는 차이지요. stack 상에서 메모리 확보하는 것은 거의 machine어로 한 명령입니다. 단지 스택포인터에 값을 더하는 것으로만으로 모든것이 끝나지요.

하지만 malloc 은 커널로부터 할당받은 메모리가 부족한지도 봐야하고,
부족하면 더 요청해야하며, 할당받은 공간을 기존 조각들과 이어놓아야하는 등
수많은 작업을 하게 됩니다.

glibc 같은 소스를 받아서 malloc 부분을 열어보시면 많이 도움이 되실 듯합니다.

xjiwoox의 이미지

여러 좋은 답변들 감사합니다.
정말 많은 도움이 됐습니다.
*^^*

s(˘∼˘*)z,·´″"`°³о$ √(´∀`√)... (˘ヘ˘ㆀ)a

Necromancer의 이미지

mastercho wrote:
힙이라는 구조는 자료구조책에 트리구조로 나오는데 -_-;

힙을 링크드 리스트로 구현하셨다는건 좀 .....

프로그램 실행시 프로그램 기본 할당 영역 외에 OS에서 추가로 할당해 주는
영역을 가리키는 heap (보통 malloc()류의 함수로 할당받죠)과
자료구조책에 나오는 heap이라고 불리는 괴짜 트리를 헷갈린거 아니에요?

용어가 같아서 그렇지 둘은 엄연히 다릅니다.

제가 heap을 링크드 리스트로 구현했다는 말은 malloc()의 블럭 관리를 링크드
리스트로 한다는 말이죠. 근데 glibc 소스 주석문 들춰보면 링크드 리스트로 힙을 관리하는거
같더군요. (이거 갠적으로 상당히 맘에 안들긴 하지만)

Written By the Black Knight of Destruction

mastercho의 이미지

:oops: 제가 착각한거 같습니다
설마 근데... malloc을... -_-; 링크드 리스트로 관리를?

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

atlacpi의 이미지

오버헤드 비교대상이라기 보다.. malloc은 동적 멤생성이란 잇점으로 봐야할것은같은디..

그래두 비교해보면.

1. "char buf[100];"이 현재 stack page안에서 만들수 있는경우.
- 이럴경우는 당근 "char buf[100]" 이넘이 훨빠르겠죠. 빠르다기 보다
오버헤드가 없죠.
2. "char buf[100];"가 현재 stack page를 넘어서는 경우.
- 이럴경우는 kernel에서 get_freepage덩가? 하여튼 이넘 불러서 새로운
page를 받고 0으로 채우고, process에게 할당해줘야 합니다.
- malloc은 실제 물리적은 메모리를 할당하진 않지만, page table을 설정
해 줘야 하고, process의 heap영역관련 struct를 손봐줘야 합니다.
- 이럴경우는 아무래두 malloc이 쬐끔 빠르지 않을까 생각됩니다. getfreepage가 생각보다 오버헤드가 크죠, 물리적인 메모리 할당할려면 kernel memory management관련 struct도 건드리니깐...--;

이상 제생각 이었습니다.

Vm~*

su2014의 이미지

그리고 heap에 대해서 논란이 있던데 glib에서는 이걸 커널 레벨에서 메모리 관리하는것이 아닌 user level에서 관리하는 것 아닌가요? 개념적으로 봐도 라이브러리가 kernel level에서 메모리까지 관리하는 건 아닐텐데 ^^;;

글구 커널 레벨에서는 buddy system과 slab로 메모리를 할당하는 것으로 아는데요 ^^

아 글구

--------------------------------------------------------------------------------
1. 함수 내부의 변수(static 말고 stack상에 유지되는...)
char buffer1[100];
2. heap을 할당받는 변수
char *buffer2;
buffer2 = (char *)calloc(1, 100);
free(buffer2);
--------------------------------------------------------------------------------

에서는 1이 빠른데 별 차이는 없구 만약에 함수 내부마다 char buffer1[100]이 필요하다면 동기화 문제만 없다면 이를 전역으로 둬서 프로그램을 짜는 편이 속도 상에는 더 낳을 거라는 점만 ^^

mastercho의 이미지

atlacpi wrote:
오버헤드 비교대상이라기 보다.. malloc은 동적 멤생성이란 잇점으로 봐야할것은같은디..

그래두 비교해보면.

1. "char buf[100];"이 현재 stack page안에서 만들수 있는경우.
- 이럴경우는 당근 "char buf[100]" 이넘이 훨빠르겠죠. 빠르다기 보다
오버헤드가 없죠.
2. "char buf[100];"가 현재 stack page를 넘어서는 경우.
- 이럴경우는 kernel에서 get_freepage덩가? 하여튼 이넘 불러서 새로운
page를 받고 0으로 채우고, process에게 할당해줘야 합니다.
- malloc은 실제 물리적은 메모리를 할당하진 않지만, page table을 설정
해 줘야 하고, process의 heap영역관련 struct를 손봐줘야 합니다.
- 이럴경우는 아무래두 malloc이 쬐끔 빠르지 않을까 생각됩니다. getfreepage가 생각보다 오버헤드가 크죠, 물리적인 메모리 할당할려면 kernel memory management관련 struct도 건드리니깐...--;

이상 제생각 이었습니다.

스택크기를 미리 좀 늘려주면 위와 같은 사항은 거의 나오지 않습니다만은 --;

그리고 재귀 호출이 없는한....대다수의 스텍재할당은 컴파일타임때 알수 있습니다

///-----추가
제가 알기론.... 동적 할당은 커널 레벨까지 가지 않습니다--;

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

Necromancer의 이미지

mastercho wrote:

제가 알기론.... 동적 할당은 커널 레벨까지 가지 않습니다--;

맞습니다.
커널 레벨에서 메모리 할당은 mmap()과 brk() 두개의 시스템 콜을
씁니다. malloc()은 userlevel에서 프로그램의 요청에 따라 현재 프로그램이
가진 메모리 중 안쓰는 부분을 할당해 주다가 모자르면 이들한테 요구를 하죠.
mmap()의 경우 munmap()으로 해제시키고요. brk()는 프로그램 크기를
조절합니다.

Written By the Black Knight of Destruction

atlacpi의 이미지

mastercho wrote:
atlacpi wrote:
오버헤드 비교대상이라기 보다.. malloc은 동적 멤생성이란 잇점으로 봐야할것은같은디..

그래두 비교해보면.

1. "char buf[100];"이 현재 stack page안에서 만들수 있는경우.
- 이럴경우는 당근 "char buf[100]" 이넘이 훨빠르겠죠. 빠르다기 보다
오버헤드가 없죠.
2. "char buf[100];"가 현재 stack page를 넘어서는 경우.
- 이럴경우는 kernel에서 get_freepage덩가? 하여튼 이넘 불러서 새로운
page를 받고 0으로 채우고, process에게 할당해줘야 합니다.
- malloc은 실제 물리적은 메모리를 할당하진 않지만, page table을 설정
해 줘야 하고, process의 heap영역관련 struct를 손봐줘야 합니다.
- 이럴경우는 아무래두 malloc이 쬐끔 빠르지 않을까 생각됩니다. getfreepage가 생각보다 오버헤드가 크죠, 물리적인 메모리 할당할려면 kernel memory management관련 struct도 건드리니깐...--;

이상 제생각 이었습니다.

스택크기를 미리 좀 늘려주면 위와 같은 사항은 거의 나오지 않습니다만은 --;

그리고 재귀 호출이 없는한....대다수의 스텍재할당은 컴파일타임때 알수 있습니다

///-----추가
제가 알기론.... 동적 할당은 커널 레벨까지 가지 않습니다--;

훔.. 먼가 잘못알고 계시는거 아닌가요?
1. stack 재할당
stack크기는 물론, 컴파일 할때 알 수있지요 하지만 elf file에 그내용이 들어가지 않습니다. 한page가 넘을때마다 page_fault가 뜨고 그때 재할당하는 겁니다. stack크기를 늘려준다 하더라도 생길 수도 있는문제지요.

2. dynamic memory allocation
하하하 웃기네요. kernel level까지 가지 않고 어떻게 동적할당을 할 수 있죠?
malloc호출하면 struct vm_area_struct mmap을 조절해야 합니다.
이건 process의 page_table을 재조정 한다는 거죠. 물론 실제로 memory를 할당하진 않고, 이영역의 memory를 access할때 page_fault가 뜨고 실제로 메모리를 할당하지요.

이과정을 kernel level까지 가지 않고 할 수 있다니 참으로 대단하십니다. 그려..

Vm~*

atlacpi의 이미지

흑기사 wrote:
mastercho wrote:

제가 알기론.... 동적 할당은 커널 레벨까지 가지 않습니다--;

맞습니다.
커널 레벨에서 메모리 할당은 mmap()과 brk() 두개의 시스템 콜을
씁니다. malloc()은 userlevel에서 프로그램의 요청에 따라 현재 프로그램이
가진 메모리 중 안쓰는 부분을 할당해 주다가 모자르면 이들한테 요구를 하죠.
mmap()의 경우 munmap()으로 해제시키고요. brk()는 프로그램 크기를
조절합니다.

윗글과 마찬가지네요.
kernel level에서 process의 메모리 영역을 확보하지 않으면, 어디서 누가 해준단 말입니까?

여기서 kernel level이라는 것이 kernel의 memory영역을 건드리지 않는다는 말같은데..

process의 메모리 영역(struct process의 멤버변수인 struct vm_area_struct mmap)은 kernel level에서 할당해제하고, process의 page_table만 조작한 경우는 물론 실제 메모리가 할당되지 않으니 별상관이 없겠지만, 이영역을 access할때는 page_fault뜨고 여기서 실제 메모리를 할당하는 과정에서 kernel memory management와 관련될 수 밖에 없습니다. 실제메모리 할당이니까요.

Vm~*

sliver의 이미지

제 생각에는 stack의 경우가 오버헤드가 더 작을듯 합니다.

먼저 stack의 경우는 단순히 stack포인터값만 감소시킴으로써 할당을 하는데 비해,
malloc의 경우는 링크드 리스트같은 자료구조를 뒤져서 할당을 합니다.
혹시 현재 프로세스의 heap공간이 부족하면 brk와 같은 시스템콜을 통해 heap공간을 늘리게 됩니다.

그리고 둘 중 어느 경우나 page fault가 나면 커널이 해야하는 일은 거의 같기 때문에 이 부분의 오버헤드는 같다고 생각합니다.

댓글 달기

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