메모리 사용량이 많은 응용 프로그램에서 메모리 부족을 방지하는 방법은 무엇입니까?C/C++

StackOverflow https://stackoverflow.com/questions/741834

  •  09-09-2019
  •  | 
  •  

문제

나는 openstreetmap xml 파일을 가져와 일반적으로 원래 크기의 약 10%인 바이너리 런타임 렌더링 형식으로 변환하는 변환기를 작성했습니다.입력 파일 크기는 일반적으로 3GB 이상입니다.입력 파일은 한꺼번에 메모리에 로드되지 않고 포인트와 폴리가 수집되면서 스트리밍된 다음 해당 파일에 대해 bsp가 실행되고 파일이 출력됩니다.최근에 더 큰 파일의 경우 메모리가 부족하여 죽습니다(문제의 파일에는 1400만 개의 포인트와 100만 개의 다각형이 있습니다).일반적으로 내 프로그램은 이런 일이 발생하면 약 1GB에서 1.2GB의 RAM을 사용합니다.가상 메모리를 2GB에서 8GB(XP 기준)로 늘려 보았지만 이 변경 사항은 효과가 없었습니다.또한 이 코드는 오픈 소스이므로 사용 가능한 RAM에 관계없이(비록 느리기는 하지만) Windows, Linux 및 Mac에서 실행되도록 하고 싶습니다.

메모리 부족을 방지하려면 어떤 기술을 사용할 수 있나요?더 작은 하위 집합으로 데이터를 처리한 다음 최종 결과를 병합하시겠습니까?내 가상 메모리 유형의 핸들러를 사용하시나요?다른 아이디어가 있나요?

도움이 되었습니까?

해결책

첫째, 32 비트 시스템에서는 페이지 파일 설정에 관계없이 항상 4GB의 메모리로 제한됩니다. (그리고 그 중에서도 Windows에서 프로세스에 2GB 만 사용할 수 있습니다. Linux에서는 일반적으로 약 3GB를 사용할 수 있습니다).

따라서 첫 번째 명백한 솔루션은 64 비트 OS로 전환하고 응용 프로그램을 64 비트로 컴파일하는 것입니다. 이를 통해 사용할 거대한 가상 메모리 공간이 제공되며 OS는 작업을 유지하기 위해 필요한 경우 PageFile 안팎으로 데이터를 교환합니다.

둘째, 한 번에 작은 기억 덩어리를 할당하는 것이 도움이 될 수 있습니다. 하나의 1GB 청크보다 456MB 덩어리의 자유 메모리를 찾는 것이 종종 더 쉽습니다.

셋째, 문제를 나누십시오. 전체 데이터 세트를 한 번에 처리하지 말고 한 번에 작은 섹션 만로드하고 처리하십시오.

다른 팁

아무데도 메모리를 누출하지 않도록 확인 했습니까?

귀하의 프로그램은 Linux에 대한 휴대용이므로 Valgrind에서 실행하여 확인하는 것이 좋습니다.

당신이 이미하고있는 것 같습니다 색소폰 XML 처리에 대한 기반 접근 방식 (한 번에 대신 XML을로드).

솔루션은 거의 항상 알고리즘을 변경하여 문제를 더 작은 부분으로 자릅니다. 물리적으로 한 번에 많은 기억을 할당하지 않고 필요한 것만 읽고 처리 한 다음 작성한 다음 작성하십시오.

알고리즘에서 필요할 때 대신 하드 드라이브를 사용하여 메모리를 확장 할 수 있습니다.

알고리즘을 분할 할 수 없다면 아마도 메모리 매핑 파일.

최악의 경우 VirtualAlloc Windows 시스템에있는 경우. 32 비트 시스템에 있다면 다음과 같은 것을 사용할 수 있습니다. 물리적 주소 확장 (PAE).

또한 프로그램에 입력 한계를두고 32 비트 및 64 비트 시스템에 대해 다른 제품을 갖는 것을 고려할 수도 있습니다.

메모리 문제가 BSP 트리를 메모리에 유지하는 것입니다. 따라서 BSP를 디스크에 보관하고 덩어리를 메모리에만 보관하십시오. 구조가 다른 트리 구조보다 더 많이 빌려 지므로 논리는 간단해야하므로 BSP에서는 매우 쉬워야합니다. 효율적이고 메모리 친화적이 되려면 더러운 플래그가있는 캐시를 가질 수 있으며 캐시 크기는 호흡 공간을 위해 사용 가능한 메모리로 설정됩니다.

Windows XP를 사용하고 있다고 가정하면 메모리 제한을 초과하고 위에서 제안한대로 코드를 재 작업 할 시간이없는 경우 /3GB 스위치를 귀하의에 추가 할 수 있습니다. boot.ini 파일을 다음 1GB의 메모리를 얻기 위해 링커 스위치를 설정하는 문제입니다.

가상 메모리는 사용중인 가상 메모리의 양이 예약 한 총 금액이고 실제 메모리 (Windows)에서는 작업 세트라고하는 메모리라는 점에서 가상 메모리가 "RAM"과 다르다는 것을 이해해야합니다. 실제로 수정되거나 잠겨 있습니다.

다른 사람이 지적했듯이 32 비트 Wind

따라서 사용자가 64 비트를 강제하거나 가상 메모리를 모니터링하고 최대 블록 크기를 32 비트 운영 체제에 의해 부과 된 한계 내부에 편안하게 맞는 것으로 캡핑하는 것이 제 조언이 될 것입니다.

나는 창에서 32 비트 벽으로 부딪 쳤지 만 Linux에서 이러한 제한 사항을 해결하는 경험이 없으므로 Windows 측면에 대해서만 이야기했습니다.

32비트 XP에서 최대 프로그램 주소 공간은 2GB입니다.그런 다음 주소 공간에 로드되는 DLL 및 드라이버로 인해 조각화가 발생합니다.마지막으로 힙 조각화 문제가 있습니다.

가장 좋은 방법은 이를 끝내고 64비트 프로세스(64비트 시스템에서)로 실행하는 것입니다.갑자기 이러한 모든 문제가 사라집니다.더 나은 힙을 사용하여 힙 조각화 효과를 완화할 수 있으며 VirtualAlloc을 사용하여 하나의 큰 연속 청크로 메모리를 확보한 다음 거기에서 메모리를 관리하여 DLL/드라이버가 조각화하는 것을 방지할 수 있습니다.

마지막으로 BSP를 프로세스 간에 분할할 수 있습니다.복잡하고 고통스럽고 솔직히 디스크에 저장하는 것이 더 쉬울 수 있지만 이론적으로는 모든 것을 상주할 수 있다면(그리고 OS보다 메모리보다 더 똑똑할 수 있다고 가정하면) 정보를 교환하는 프로세스 그룹을 가짐으로써 더 나은 성능을 얻을 수 있습니다. 파일 버퍼링을 처리할 수 있습니다...이는 큰 경우입니다).각 프로세스에는 훨씬 적은 메모리가 필요하므로 2GB 주소 공간 제한에 도달해서는 안 됩니다.물론 훨씬 더 빠르게 RAM을 소모하고 교체할 수 있습니다.

더 작은 청크를 할당하여 주소 공간 조각화의 영향을 완화할 수 있습니다.이는 다른 불쾌한 부작용을 가져오지만, 성공적으로 할당하지 못한 경우 점점 더 작은 메모리 청크를 가져오는 백오프 정책을 따를 수 있습니다.종종 이 간단한 접근 방식을 사용하면 그렇지 않을 때 작동하지만 나머지 시간에는 가능한 한 잘 작동하는 프로그램을 얻을 수 있습니다.

64비트 컴퓨팅이 다른 컴퓨팅보다 훨씬 더 좋게 들리지 않나요?

포인트에 대한 메모리를 어떻게 할당하고 있습니까? 한 번에 하나씩 포인트를 할당하고 있습니까 (예 : PT = 새로운 포인트). 포인트 크기에 따라 일부 메모리가 낭비 될 수 있습니다. 예를 들어 Windows 메모리에서 16 바이트의 배수에 할당되므로 1 바이트를 할당해도 OS는 실제로 16 바이트를 할당합니다.

이 경우 메모리 할당자를 사용하면 도움이 될 수 있습니다. STL 할당자를 사용하여 빠른 점검을 수행 할 수 있습니다. (포인트 클래스의 새 연산자를 오버로드하고 STL 할당자를 사용하여 'Malloc'또는 기본 새 연산자 대신 메모리를 할당하십시오).

최적의 방식으로 메모리를 할당하고 거래하지 않을 수 있습니다. 다른 사람들이 지적했듯이, 당신은 기억을 유출하고 그것을 알지 못할 수 있습니다. 메모리 할당 디버깅 및 최적화에는 시간이 걸립니다.

메모리 사용을 최적화하는 데 시간을 소비하고 싶지 않다면 보수적 인 쓰레기 수집가? malloc ()/new and free ()의 플러그인 교체품입니다. 실제로 Free ()는 NO-OP이므로 프로그램에서 해당 호출을 제거 할 수 있습니다. 대신, 당신이 당신의 프로그램을 직접 최적화하고 이전에 제안한대로 메모리 풀을 관리한다면, 당신은 CGC가 이미 당신을 위해하고있는 많은 작업을 수행하게 될 것입니다.

출력과 입력을 스트리밍해야합니다. 출력 형식이 스트림 지향이 아닌 경우 두 번째 패스를 고려하십시오. 예를 들어, 출력 파일이 데이터의 점검 합계/크기로 시작하면 첫 번째 패스에 공간을두고 나중에 해당 공간을 찾아보고 쓰십시오.

이진 대화에 txt를 수행하는 것처럼 들리므로 왜 메모리에 전체 데이터가 있어야합니까?.
TXT (XML)에서 원시를 읽은 다음 BinaryStream에 저장할 수 없습니까?

메모리 크기 독립이 되려면 크기 독립적 인 알고리즘이 필요합니다. RAM의 크기에 관계없이, 제어중인 메모리 사용량이 없다면 국경에 부딪 힐 것입니다.

약간의 출력을 생성하는 데 사용할 수있는 최소한의 정보를 살펴보십시오. 그런 다음 입력을이 크기의 덩어리로 나누는 방법을 생각해보십시오.

이제 쉬운 것 같지 않습니까? (내가 할 필요가 없어서 다행입니다 :))

64 비트 머신으로 전환 할 필요는 없으며 다른 사람이 제안한 1000 개가 필요합니다. 필요한 것은 더 사려 깊은 알고리즘입니다.

이 상황을 도울 수있는 일은 다음과 같습니다.

  • Windows에있는 경우 파일 맵을 사용합니다 (샘플 코드). 이렇게하면 단일 버퍼 포인터를 통해 파일에 액세스 할 수 있습니다. 최근 버전의 Linux 커널은 비슷한 메커니즘을 가지고 있습니다.
  • 가능하고 할 수있는 것처럼 보이면 파일을 순차적으로 스캔하고 메모리 내 DOM을 생성하지 마십시오. 이렇게하면 메모리 요구 사항뿐만 아니라로드 시간이 크게 줄어 듭니다.
  • 풀링 된 메모리를 사용하십시오! 당신은 아마도 노드, 포인트 및 것과 같은 많은 작은 객체가있을 것입니다. 풀링 된 메모리를 사용하여 도움을 줄 수 있습니다 (관리되지 않는 언어를 사용하고 있다고 가정합니다. 풀링 할당 및 메모리 풀을 검색하십시오).
  • 관리되는 언어를 사용하는 경우 적어도이 특정 부분을 관리되지 않은 언어로 옮기고 메모리 및 파일 판독을 제어하십시오. 관리 언어는 메모리 발자국과 성능 모두에서 사소한 오버 헤드를 가지고 있습니다. (예, 이것이 "C ++"태그가 있다는 것을 알고 있습니다 ...)
  • 한 번에 최소의 데이터 만 읽고 처리하는 내장 알고리즘을 설계하려고 시도하면 메모리 요구 사항이 줄어 듭니다.

마지막으로 복잡한 작업에는 복잡한 조치가 필요하다는 점을 지적하겠습니다. 8GB의 RAM이있는 64 비트 기계를 감당할 수 있다고 생각되면 "파일 읽기 메모리, 프로세스 데이터, 출력 쓰기"알고리즘을 사용하여 하루가 걸리더라도 하루가 소요됩니다.

그것에 대한 좋은 기술이 있고, 일부 인스턴스를 파일에 저장하는 것입니다.

이 기술은 Doxygen과 같은 많은 오픈 소스 소프트웨어에서 많은 양의 메모리가 필요할 때 확장 가능합니다.

이것은 오래된 질문이지만 최근에 같은 일을했기 때문에 ....

간단한 대답은 없습니다. 이상적인 세상에서는 거대한 주소 공간 (예 : 64 비트)과 엄청난 양의 물리적 메모리가있는 기계를 사용합니다. 거대한 주소 공간만으로는 충분하지 않거나 단지 스래쉬 일 것입니다. 이 경우 XML 파일을 데이터베이스로 구문 분석하고 적절한 쿼리를 사용하여 필요한 것을 꺼냅니다. 아마도 이것이 OSM 자체가하는 일입니다 (세상은 약 330GB라고 생각합니다).

실제로 나는 여전히 편의성 때문에 XP 32 비트를 사용하고 있습니다.

공간과 속도 사이의 트레이드 오프입니다. 시간이 얼마나 걸리는지 신경 쓰지 않는 메모리에서 거의 모든 일을 할 수 있습니다. STL 구조를 사용하면 원하는 것을 구문 분석 할 수 있지만 곧 메모리가 부족할 수 있습니다. 교체하는 자신의 할당자를 정의 할 수 있지만, 맵, 벡터, 세트 등이 실제로 무엇을하고 있는지 알지 못하기 때문에 비효율적입니다.

내가 32 비트 기계의 작은 발자국에서 작동하게 만드는 유일한 방법은 내가하고있는 일과 작업을 덩어리로 나눌 때 필요한 일에 대해 매우 신중하게 생각하는 것이 었습니다. 메모리 효율성 (~ 100MB를 초과하지 않음)이지만 크게 빠르지는 않지만 중요하지 않습니다. XML 데이터를 얼마나 자주 구문 분석해야합니까?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top