리눅스의 disk cache방식으로 인한 속도 저하

dsaint31의 이미지

이미지 프로세싱 프로그램을 작성하는중인데...
리눅스의 disk cache로 인한 문제에 부딪힌 듯합니다.

redhat enterprise버전에서 테스팅중 윈도우에선 안 부딪힌 문제가 생겼습니다.

프로그램은 약 1G정도의 메모리를 malloc하여 사용하고 이 메모리의 값을 세팅하기 위해 1~1.5G정도의 파일을 로딩합니다. 문제는 linux가 파일을 로딩할때 cached 영역에 로딩한 파일들을 캐싱하고, 프로그램에서도 해당 파일의 내용을 배열로 가지고 있어서 중도에 free 메모리가 7000k정도로 고갈되게 되더군요.(속도를 위해서 내부에서 배열로 거의 파일의 데이터를 가지고 있습니다. 이덕에 사용되는 메모리가 거의 곱절로 늘어난다는....) 문제는 아직 파일을 로딩하는 부분이 남아있기 때문에 이경우 갑자기 프로그램 속도가 무지 느려집니다. fread부분입니다..

제가 알기로 free명령어를 쳐서 buffer, cached, free는 모두 애플리케이션이 요구시 사용가능한 영역으로 알고 있습니다. 비록 free부분이 7000k라고 해도 필요하다면 cached에서 가져와서라도 작업을 해야하는데...

문제는 cache에 있던 이전 로딩한 파일의 disk cache가 file에 스왑되고... 현재 로딩중인 파일을 메모리에 적재하는지 갑자기 너무 느려지네요.

free(malloc의 해제위한)로 해제를 다 해도 프로그램이 종료한 후에도 cached 영역은 보다 오랫동안 유지되더군요. 결국 제 프로그램이 malloc으로 잡았던 1G만이 free영역으로 다시 반환되어서 여러번 프로그램을 돌리면 마치 메모리 leak이 있는 것처럼 두번째엔 무지 느립니다.(첫번째보다 보다 빨리 free영역이 7000k밑으로 도달해서 그렇습니다.)

memusage와 valgrind로 leak여부는 확인했는데 leak문제는 아니더군요. 첨에 leak을 의심했기 때문에 __;;

사실 리눅스에서 프로그램 경험이 많은 편이 아니라서 좀 답답하네요. __;; disk cache를 위해서 cached가 많이 잡히는 건 좋은데... 지금 당장 필요한 파일 로딩할때 이제 안 쓰일 이전 disk cache로 인해 속도가 뚝 떨어지면 쩝...

어떤 해결책이 있을지 고견을 부탁드립니다.

p.s.
open에서 O_DIRECT flag를 주면 disk cache를 피해서 제 프로그램의 버퍼로 곧장 읽어 온다고 하더군요. 커널이 2.6.x대라 가능할 걸로 생각하고 시도 했는데.... read에서 계속 -1을 반환해서 이것도 진행하다 우선 정지시킨 상황입니다. 좀 알고리즘이 복잡한 프로그램이라 fread쓰던 부분을 read로 고치는 것도 그리 쉬울거 같지 않구요.(설계를 그리 잘 한 경우가 아니고 오직 알고리즘 구현에 신경쓰다보니 변경이 용이하진 않아서요. ㅠㅠ)
이 방법에 대한 예제가 있으시면 좀 올려주시면 정말 감사하겠습니다.

hb_kim의 이미지

디스크 캐시에 쓰는 메모리는 거의 free 메모리나 마찬가지 입니다. 언제건 필요한 만큼 꺼내서 쓸수 있다는것이니 신경을 안쓰셔도 됩니다.

이미지 프로세싱을 하신다고 했으니 데이터 액세스를 국소화하는것이 제일 일반적인 방법론이 되겠군요. 큰 배열을 잡고 파일 전체를 한번에 로딩하려 시도하면 아무래도 말씀하신것 같은 문제가 발생하겠죠.

dsaint31의 이미지

문제는 항상 느린게 아니라는 거라서요. ^^;;

우선 cached가 적을 땐, 여기선 메모리의 free영역(free커맨드나 TOP로 봤을때)이 7000k수준일때 정말 극심하게 느려집니다. 이때 다른 제가 가진 배열등에서의 연산은 문제가 없는데, fread가 시도되면 넘 느려지더군요. (물론 7000k일때도 cached만 가득이지 buffer와 cacehd를 합치면 메모리 남아돌죠. --;;)

cached가 free메모리랑 다름 없다고 저도 알고 있었는데... 이유를 잘 모르겠네요. __;;

kimsk99의 이미지

memory mapped file를 사용해보면 어떨까요?

익명 사용자의 이미지

cached는 free메모리와는 조금 다르죠..

Linux에서 메모리를 관리하는 방식은
최대한 그 메모리가 쓰이는 시점에서 실제 메모리를 page테이블에 등록을 합니다(COW)
즉 user공간에서 1G를 할당을 했다고 하더라도.. kernel영역에선 메모리 zone영역의 크기만 늘려놨을뿐.. page table을 이용해서 virtual메모리를 물리메모리로 할당을 안하죠.
실제 할당되는 시점은 user프로그램이 그 영역을 접근시도할려고 할때 page fault가 발생(page table엔 추가가 안되어있어서죠) 하고 그때 할당을 합니다.

cached가 가득차있고, user프로그램에서 할당영역을 쓸려고 접근할때, page fault가 나서 page table을 채울려할때!! 실제 물리메모리의 가용영역이 부족하면 swap을 하게됩니다. 그 swap이 무지 시간을 잡아먹는셈이죠..

몇가지 방법이 있긴하겠네요..
1. swap되는 시점을 빨리한다.
- swap이 가장 메모리가 적은 시점에서 수행되면서 생기는 문제현상으로 swapd에서 얼마이하일때 swap될턴데.. 그걸 값을 조금 키워주면 될듯합니다..
2. lock memory를 이용합니다.
- malloc을 할때 위에서 설명해드렸다시피 실제 page table을 이용 메모리를 할당하지 않고, zone영역만 늘린다고 했는데요. lock memory를 이용하면 malloc하는 시점에서 page table을 이용 할당하고, swap하지 않습니다.
http://www.gnu.org/software/libc/manual/html_node/Locking-Pages.html#Locking-Pages
3. 물리메모리를 하다 사서 키운다.
- 1GB얼마 안합니다. 하나 사서 끼우는게 정신건강에도 도움이 되지 않을까요?ㅎㅎ

체스맨의 이미지

원인은 추측하고 계신듯한데, 그렇다면 전체 소스 공개는 힘드실테니, 문제를 발생시키는 소스를 작성하셔서 올려보시면 어떨까요? 실제 실행해보지 않고서는 다른 분들도 예측하기 어려울 듯 싶은데요.

Orion Project : http://orionids.org

dsaint31의 이미지

결국 O_Direct를 선택했습니다.
가장 수정이 덜한 방법이었습니다. 여러 답변 감사합니다.

답변을 통해서 메모리 페이징에 대해서 좀더 알게 되어 기쁘네요.
(^^)(__) 꾸벅

익명 사용자의 이미지

bestyty wrote:
cached는 free메모리와는 조금 다르죠..

Linux에서 메모리를 관리하는 방식은
최대한 그 메모리가 쓰이는 시점에서 실제 메모리를 page테이블에 등록을 합니다(COW)
즉 user공간에서 1G를 할당을 했다고 하더라도.. kernel영역에선 메모리 zone영역의 크기만 늘려놨을뿐.. page table을 이용해서 virtual메모리를 물리메모리로 할당을 안하죠.
실제 할당되는 시점은 user프로그램이 그 영역을 접근시도할려고 할때 page fault가 발생(page table엔 추가가 안되어있어서죠) 하고 그때 할당을 합니다.

cached가 가득차있고, user프로그램에서 할당영역을 쓸려고 접근할때, page fault가 나서 page table을 채울려할때!! 실제 물리메모리의 가용영역이 부족하면 swap을 하게됩니다. 그 swap이 무지 시간을 잡아먹는셈이죠..

몇가지 방법이 있긴하겠네요..
1. swap되는 시점을 빨리한다.
- swap이 가장 메모리가 적은 시점에서 수행되면서 생기는 문제현상으로 swapd에서 얼마이하일때 swap될턴데.. 그걸 값을 조금 키워주면 될듯합니다..
2. lock memory를 이용합니다.
- malloc을 할때 위에서 설명해드렸다시피 실제 page table을 이용 메모리를 할당하지 않고, zone영역만 늘린다고 했는데요. lock memory를 이용하면 malloc하는 시점에서 page table을 이용 할당하고, swap하지 않습니다.
http://www.gnu.org/software/libc/manual/html_node/Locking-Pages.html#Locking-Pages
3. 물리메모리를 하다 사서 키운다.
- 1GB얼마 안합니다. 하나 사서 끼우는게 정신건강에도 도움이 되지 않을까요?ㅎㅎ

1GB를 잡고 읽어들이시는 것을 보니 아무래도 physical memory가 그 이상 되시는듯. mlockall하시면 다르지 않겠습니까? mlockall의 semantics로 봐서는 한 번에 몽땅 다 allocate할 것 같은데요.

또한 데이타가 page out되면 원래 의도가 무색해지지 않겠습니까? 특히 살아 있으면서 계속적으로 다른 데이타를 처리하는 경우라면 더욱 그렇겠죠.

댓글 달기

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