std::list의 메모리 효율

kcando의 이미지

레드햇 8.2, gcc 3.2 환경에서 아래와 같이 list에 100만개의 정수를 입력하였더니 메모리를 약 15796k바이트 사용하드라고요. 또하나 덧붙이자면 함수의 마지막에서 int_list.clear()를 호출하여도 메모리가 반환이 되지 않더군요.

왜 이러한 현상이 일어나는지 궁금합니다.

미리 감사드립니다.

void testHugeList()
{
  std::list<int> int_list;
  for (int i = 0; i < 1000000; ++i) {
    int_list.push_back(i);
  }
}
see2002의 이미지

STL에서 알아서 메모리를 해제(관리)해주는거 아닌가요?
list.clear()는 list가 담고있는 값을 비워줄뿐, 단순히 메모리를 해제하는것은 아닌걸로 알고있습니다만...

B00m의 이미지

clear 하는것은 가지고 있던 값들을 모두 지우는 것이지 실제적인 메모리를 지우지것은 아닙니다..

물론 stl 의 구현에 따라 다르겠지만 잦은 메모리 재할당을 막기 위해 일반적으로는 clear 해도 바로 메모리를 반환하게 구현되어 있지는 않습니다.

참고적으로 effective stl 에 보면 swap 을 이용해서 쓸데 없는 메모리를 반환하는 방법이 있네요..

그리고 메모리가 사용량이 걱정되신다면 list 보다는 vector 가 좋을거 같습니다.

simpid의 이미지

제가 리눅스는 잘 모르지만..
Windows의 경우나(제가 그나마 아는거...) 상식적으로 OS란놈에 대해 생각해 볼때....

메모리를 할당할때마다 시스템콜(OS차원에서의 지원)을 하는건 아닙니다.
보호모드에서 동작하는 OS에서 시스템콜은 성능저하를 발생하니까요.

사용자가 malloc이나 new 등으로 메모리를 요구하면 컴파일할때 같이 링크된 런타임 라이브러리의 메모리 할당 코드가 메모리를 할당해 줌니다.

그러니까... 사용자가 요구하면 런타임라이브러리는 자신이 갖고 있는 메모리가있다면.. 할당해서 사용자에게 돌려주고..
자신이 갖고 있는 메모리가 없다면.. OS에 요청해서.. 큰 덩어리를 받아 다시 그걸 나눠서 사용자에게 돌려줍니다.

그러니까.. .STL에서 할당된 list를 clear하더라도.. 런타임라이브러리에서 free가 되는거지.. 프로세스에서 OS로 되돌려 주는건 아니란 거죠..
그 돌려주는 시점은 OS마다 다를껍니다.
(Windows의 경우 윈도우를 최소화할때나 시스템에 메모리가 부족해 질때 메모리가 프로세스에서 OS로 되돌려지는걸 확인할 수 있습니다.)

제가 리눅스를 잘 모르니까... 이 문제에 대해 단정할 순 없지만...
일반적으로 OS는 그렇단 겁니다.

님은 STL list에 int형을 넣으셨으니까.. clear()만으로 완벽하게 메모리 정리가 되는거니까.. 걱정하실꺼 없을것 같습니다.

그래도 걱정된다면... clear()한다음... 다시 할당해 보세요.. .사용중인 메모리가 더 늘지는 않을껍니다. .... 아마도~~~ ^^;

errai의 이미지

지금 갑자기 궁금해져서 gcc 3.2.2의 stl 소스코드를 뒤져보았습니다만,
clear()가 호출되면 메모리를 해제 해줍니다.

코드에 보면 clear가 호출될때 deallocate 함수가 호출되어
뭔가 이상한 짓을 하는것 같습니다. 안에 소멸자도 보이고.. 무지
복잡하네요 ^^ 간단히 이해할 수 있는것 같지가 않습니다.
몇가지 간단한 코드로 테스트 해봐도 기존의 메모리 구현 방식과 다르게
STL은 함수가 종료 되어도 메모리가 사라지지 않더군요.
꼭 소멸자를 불러 줘야 하는것인지. 더 공부해 보려다가 귀찮아졌습니다. :-(

결론은 STL 자체에서 사용하는 Allocator에 의해서 메모리 관리를 하므로
전혀 문제될 것이 없다! 즉 위에서 설명해주신 분들이 말씀이 다 맞는것 같습니다.

kcando의 이미지

우선 답변에 감사드립니다.

데몬에서 사용 중이라서 사실 clear() 호출 시점에 메모리 해제가 되느냐 안되느냐는 그리 큰 문제는 아니구요(clear()를 호출하면 메모리를 더 사용하더군요).

더 큰 문제는 왜 4바이트 짜리 항목을 100만개 만들었을 때 15796k바이트 씩이나 사용하는가 하는 것입니다.

간단히 계산하자면 4*1000000 = 약 3906k바이트인데 거의 4배의 메모리를 사용하네요.

저 정도의 계산이라면 사용상의 무리가 있지 않을까요?

다시 한번 감사드립니다.

서지원의 이미지

simpid wrote:
제가 리눅스는 잘 모르지만..
Windows의 경우나(제가 그나마 아는거...) 상식적으로 OS란놈에 대해 생각해 볼때....

메모리를 할당할때마다 시스템콜(OS차원에서의 지원)을 하는건 아닙니다.
보호모드에서 동작하는 OS에서 시스템콜은 성능저하를 발생하니까요.

사용자가 malloc이나 new 등으로 메모리를 요구하면 컴파일할때 같이 링크된 런타임 라이브러리의 메모리 할당 코드가 메모리를 할당해 줌니다.

잘못 알고 계십니다. 메모리를 할당할 때마다(malloc마다) 시스템콜을 합니다.

clhitter의 이미지

list에 들어가는 int value 들만 생각하면 4 byte이지만
stdlist는 doubly linked list이므로 추가로 4byte의 pointer 두개가 추가되게 됩니다.
결국 node 하나 마다 4byte가 아니라 12byte가 소요되는 것이죠
근데 왜 3배가 아니라 4배인지는 잘 모르겠네요 ^^

위에 어떤 분이 답변하신 것 처럼 메모리 효율이 중요하시다면 vector를 사용하시는게 좋습니다. array와 거의 비슷한 메모리 구조를 사용하거든요.

simpid의 이미지

서지원 wrote:
simpid wrote:
제가 리눅스는 잘 모르지만..
Windows의 경우나(제가 그나마 아는거...) 상식적으로 OS란놈에 대해 생각해 볼때....

메모리를 할당할때마다 시스템콜(OS차원에서의 지원)을 하는건 아닙니다.
보호모드에서 동작하는 OS에서 시스템콜은 성능저하를 발생하니까요.

사용자가 malloc이나 new 등으로 메모리를 요구하면 컴파일할때 같이 링크된 런타임 라이브러리의 메모리 할당 코드가 메모리를 할당해 줌니다.

잘못 알고 계십니다. 메모리를 할당할 때마다(malloc마다) 시스템콜을 합니다.

그렇습니까?
그럼.. Windows와 Linux의 차이점중 하나겠군요.

시스템콜을 해서 커널모드로 진입시 발생하는 성능저하가 있을텐데...
작은 크기의 메모리를 malloc으로 여러번(아주~) 할당하면.. 성능저하가 있을지도 모르겠군요.

서지원의 이미지

simpid wrote:
서지원 wrote:
simpid wrote:
제가 리눅스는 잘 모르지만..
Windows의 경우나(제가 그나마 아는거...) 상식적으로 OS란놈에 대해 생각해 볼때....

메모리를 할당할때마다 시스템콜(OS차원에서의 지원)을 하는건 아닙니다.
보호모드에서 동작하는 OS에서 시스템콜은 성능저하를 발생하니까요.

사용자가 malloc이나 new 등으로 메모리를 요구하면 컴파일할때 같이 링크된 런타임 라이브러리의 메모리 할당 코드가 메모리를 할당해 줌니다.

잘못 알고 계십니다. 메모리를 할당할 때마다(malloc마다) 시스템콜을 합니다.

그렇습니까?
그럼.. Windows와 Linux의 차이점중 하나겠군요.

시스템콜을 해서 커널모드로 진입시 발생하는 성능저하가 있을텐데...
작은 크기의 메모리를 malloc으로 여러번(아주~) 할당하면.. 성능저하가 있을지도 모르겠군요.

음.. 제가 잘못 알고 있었던 것 같습니다. malloc는 libc에 있으면서, 필요할 때마다 SYS_mmap syscall을 호출하는 것 같습니다.

mtorange의 이미지

clhitter wrote:
list에 들어가는 int value 들만 생각하면 4 byte이지만
std::list는 doubly linked list이므로 추가로 4byte의 pointer 두개가 추가되게 됩니다.
결국 node 하나 마다 4byte가 아니라 12byte가 소요되는 것이죠
근데 왜 3배가 아니라 4배인지는 잘 모르겠네요 ^^

위에 어떤 분이 답변하신 것 처럼 메모리 효율이 중요하시다면 vector를 사용하시는게 좋습니다. array와 거의 비슷한 메모리 구조를 사용하거든요.

잃어버린 4byte는 malloc 자체의 의 overhead입니다. malloc으로 할당한 memory chunk자체의 정보를 저장하기 위해서 4byte를 사용합니다. 따라서 16byte가 소모되는게 맞습니다.

댓글 달기

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