Linux 환경에서 C++의 메모리 매핑을 이해해 보세요.

Linux 환경에서 C++의 메모리 매핑을 이해해 보세요.

내 임무는 메모리 맵을 탐색하고 이를 활용할 수 있는지 확인하는 것입니다.

저는 이 개념과 코딩 방법을 이해하려고 노력하고 있습니다. 아래 비디오와 블로그 게시물의 코드를 시험해 보았지만 쉽게 재현할 수 있도록 여기에서도 단계를 반복할 것입니다. Linux 시스템에서 C++(gcc 버전 11.2.0)를 사용하고 있습니다.

https://www.youtube.com/watch?v=m7E9piHcfr4

https://bertvandenbroucke.netlify.app/2019/12/08/memory-mapping-files/

이게 내 코드야 write_mmap.cpp

#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <iostream>

int main() {
  // reading
  int file_read = open("test.dat", O_RDONLY, 0);
  // writing
  int file_write = open("test.dat", O_CREAT | O_RDWR,
                      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
  posix_fallocate(file_write, 0, 4096);

  char *buffer = reinterpret_cast<char*> (mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, file_write, 0));

  for (int i = 0; i < 4096; i++) {
    // Change each upper-case A to lowercase in the file
    if (buffer[i] == 'A') {
      buffer[i] = 'a';
    }
  }
}

test.dat이렇게 생겼어

Name,marker1,marker2,marker3,marker4
barc1,AA,AB,BB,--
barc2,AB,AA,BB,--

명령을 실행한 후

g++ write_mmap.cpp
./a.out

보니까 이렇게 test.dat바뀐거 같은데

Name,marker1,marker2,marker3,marker4
barc1,aa,aB,BB,--
barc2,aB,aa,BB,--

이것이 내가 원하는거야. 여기서 많은 것에 대해 잘 모르겠습니다. 우선, test.dat메모리 매핑 파일인가요? 디렉토리에 있을 때 ls파일 시스템에 보이는데 가상 메모리 어딘가에 있는 걸까요? 그렇다면 가상 메모리 어디에 저장되어 있는지 알 수 있는 방법이 있을까요?

제가 작성할 때는 원래 텍스트 파일이었는데 스크립트가 완료된 후 바이너리 파일이 된 이유는 무엇입니까? nano다음으로 파일을 열 때

Name,marker1,marker2,marker3,marker4
barc1,aa,aB,BB,--
barc2,aB,aa,BB,--
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^

또한 메모리 매핑에 대해 명확히 하고 싶습니다.

  1. 이 파일은 현재 RAM에 있습니다. 그렇죠? 어떤 프로그램(언어에 관계없이)이 메모리의 이러한 부분을 읽을 수 있습니까?

  2. 이 파일에 "북마크"를 설정할 수 있는 방법이 있습니까? 그렇다면 컴퓨터가 특정 섹션부터 파일을 읽기 시작하도록 하려면 주소 A에서 주소 B로 읽도록 지시할 수 있습니까?

답변1

이 파일은 현재 RAM에 있습니다. 그렇죠?

아니요, 파일이 RAM에 없습니다. 파일의 일부는 RAM에 있습니다. 두 번째 매개변수는 mmap파일 매핑에 사용되는 메모리 세그먼트의 크기를 요청합니다. 마지막 매개변수는 mmap파일 내의 위치입니다. 따라서 귀하의 예에서는 파일 시작 부분부터 4Kb를 매핑합니다. 원본 파일의 크기가 4097바이트인 경우 마지막 바이트는 매핑되지 않습니다. mremap파일의 다른 청크로 이동할 수 있습니다 .

메모리가 어디에 있는지 알고 싶다면 의 반환을 살펴보세요 mmap. 변수는 buffer정확히 파일이 매핑된 프로세스 메모리의 위치를 ​​가리키는 포인터입니다.

어떤 프로그램(언어에 관계없이)이 메모리의 이러한 부분을 읽을 수 있습니까?

예. 하지만 조금 복잡합니다.

mmap첫째, then 을 수행하면 fork자식은 포인터를 상속받고 정확히 동일한 메모리에 액세스할 수 있습니다.

둘째, 다른 프로세스(언어에 관계없이)가 동일한 파일과 파일 내의 동일한 블록을 매핑하기로 결정한 경우 동일한 메모리에 액세스할 수 있지만 해당 프로세스의 주소 공간에 매핑됩니다. 즉, 두 프로세스가 여전히 파일 내용을 놓고 싸울 수 있지만 동일한 바이트를 가리키는 포인터는 수치적으로 다릅니다.

크기와 오프셋을 혼합할 수 있다는 점을 잊지 마십시오. 첫 번째 응용 프로그램은 오프셋 0에서 4Kb 파일을 매핑합니다. 다른 애플리케이션은 오프셋 1024에서 동일한 파일의 1Kb를 매핑합니다. 따라서 하나의 1Kb 블록만 경합 대상이 됩니다. 이 혼합은 매우 복잡할 수 있습니다. 이 문제를 해결하기 위해(또는 메모리 관리를 더 쉽게 만들기 위해) "페이지"가 ​​있습니다. 이는 오프셋이 페이지 크기의 배수여야 한다는 요구 사항 때문입니다.

이 파일에 "북마크"를 설정할 수 있는 방법이 있습니까? 그렇다면 컴퓨터가 특정 섹션부터 파일을 읽기 시작하도록 하려면 주소 A에서 주소 B로 읽도록 지시할 수 있습니까?

아니요, 북마크가 없습니다. 하지만 6번째와 2번째 매개변수는 mmap이 작업을 효과적으로 수행할 수 있습니다.마지막 매개변수이자 주소입니다.두번째마지막 + 두 번째 매개변수입니다 mmap.

그런데 읽기 위해 파일을 열 필요는 없습니다. 이 경우에는 중복됩니다. 이제 동일한 파일을 가리키는 두 개의 파일 설명자가 있지만 읽기 전용 파일 설명자를 무시하고 있습니다. 범죄는 아니지만 잠재적인 메모리 누수 가능성이 있습니다.

^@이는 파일을 열 때 볼 수 있는 nano많은 내용입니다 posix_fallocate. 이 함수는 파일 크기가 맞는지 확인합니다 mmap. 기술적으로 posix_fallocate파일이 요청된 세그먼트를 채울 만큼 충분히 크다면 호출할 필요가 없습니다 mmap. 하지만 파일이 너무 작다면 posix_fallocate확대하세요. 따라서 이제 시작 부분에는 이전 데이터가 채워지고 끝 부분에는 0( ^@- in 0 bytes nano) 으로 채워진 4Kb 파일이 생겼습니다.

관련 정보