문제

나는 많은 작은 블록(32-64b)을 할당하고 할당 해제하는 단일 스레드 임베디드 애플리케이션을 가지고 있습니다.캐시 기반 할당자를 위한 완벽한 시나리오입니다.그리고 비록 제가 작성하려고 노력할 수는 있지만 그것은 시간 낭비일 가능성이 높으며 이미 최전선에 있는 일부 솔루션만큼 잘 테스트되고 조정되지 않을 것입니다.

그렇다면 이 시나리오에 사용할 수 있는 가장 좋은 할당자는 무엇입니까?

메모:저는 시스템에서 Lua 가상 머신(할당의 80% 이상 원인)을 사용하고 있으므로 할당 성능을 높이기 위해 스택 할당을 사용하도록 코드를 간단하게 리팩터링할 수 없습니다.

도움이 되었습니까?

해결책

메모리 파편화에 문제가 있었기 때문에 최근 에이 주제에 대한 연구를했습니다. 결국 우리는 GNU LIBC의 구현을 유지하고 필요한 경우 애플리케이션 수준 메모리 풀을 추가하기로 결정했습니다. 더 나은 조각화 행동을 가진 다른 할당자가 있었지만, 우리는 그들과 충분히 편안하지 않았다. GNU는 그 뒤에 오랜 역사의 이점을 가지고 있습니다.

당신의 경우 그것은 정당화 된 것 같습니다. VM을 고칠 수 없다고 가정하면 작은 할당은 매우 낭비됩니다. 전체 환경이 무엇인지 모르겠지만 VM에서 Malloc/Realloc/Free로 통화를 포장하여 작은 수영장 용으로 설계된 핸들러로 전달할 수 있습니다.

다른 팁

CI의 과거 프로젝트에서 우리는 임베디드 시스템을 포함한 광범위한 플랫폼에서 라이브러리 실행을위한 자체 메모리 관리 루틴을 구현하는 길을 따라갔습니다. 도서관은 또한 많은 수의 작은 버퍼를 할당하고 해제했습니다. 비교적 잘 운영되었으며 구현하기 위해 많은 양의 코드를 사용하지 않았습니다. 당신이 직접 무언가를 개발하고 싶을 때 그 구현에 대한 약간의 배경을 줄 수 있습니다.

기본 구현에는 세트 크기의 버퍼를 관리하는 일련의 루틴이 포함되었습니다. 루틴은 Malloc () 및 free () 주변의 포장지로 사용되었습니다. 우리는 이러한 루틴을 사용하여 자주 사용하는 구조물의 할당을 관리하고 세트 크기의 일반 버퍼를 관리하기 위해 사용했습니다. 관리중인 각 유형의 버퍼를 설명하는 데 구조가 사용되었습니다. 특정 유형의 버퍼가 할당되면 Malloc () 블록의 메모리 (자유 버퍼 목록이 비어있는 경우). 즉, 10 바이트 버퍼를 관리하는 경우 단편화를 줄이기 위해 100 개의 버퍼를위한 공간을 포함하는 단일 malloc ()을 만들 수 있습니다.

각 버퍼의 전면에는 자유 목록에서 버퍼를 체인하는 데 사용되는 포인터가 있습니다. 100 버퍼가 할당되면, 각 버퍼는 자유 목록에서 함께 연결됩니다. 버퍼가 사용되면 포인터가 널로 설정됩니다. 또한 버퍼의 "블록"목록을 유지하므로 실제 Malloc'd 버퍼 각각에서 무료 ()를 호출하여 간단한 정리를 수행 할 수 있습니다.

동적 버퍼 크기의 관리를 위해 버퍼의 크기를 알려주는 각 버퍼의 시작 부분에 Size_T 변수를 추가했습니다. 그런 다음 버퍼가 해제 될 때 버퍼를 다시 넣을 버퍼 블록을 식별하는 데 사용되었습니다. 우리는 Malloc () 및 free ()에 대한 교체 루틴을 가지고 있었는데, 이는 버퍼 크기를 얻은 다음 버퍼를 자유 목록에 넣기 위해 포인터 산술을 사용했습니다. 우리는 또한 우리가 관리하는 버퍼의 큰 양에 제한이있었습니다. 이 한계보다 큰 버퍼는 간단하게 malloc'd이며 사용자에게 전달되었습니다. 우리가 관리 한 구조의 경우, 특정 구조의 할당 및 해방을위한 래퍼 루틴을 만들었습니다.

결국 우리는 또한 사용자가 사용하지 않은 메모리를 정리하도록 요청할 때 쓰레기 수집을 포함하도록 시스템을 진화 시켰습니다. 우리는 전체 시스템을 제어했기 때문에 시간이 지남에 따라 시스템의 성능을 높이기 위해 다양한 최적화가있었습니다. 내가 언급했듯이, 그것은 아주 잘 작동했습니다.

나는 파티에 조금 늦었지만 최근에 발견하고 테스트 한 임베디드 시스템에 대해 매우 효율적인 메모리 할당자를 공유하고 싶습니다. https://github.com/dimonomid/umm_malloc

이것은 ARM7과 함께 작동하도록 특별히 설계된 메모리 관리 라이브러리입니다. 개인적으로 PIC32 장치에서 사용하지만 16 비트 및 8 비트 장치에서 작동해야합니다 (16 비트 PIC24에서 테스트 할 계획이 있지만 I 아직 테스트하지 않았습니다)

나는 기본 할당 자로 조각화에 의해 심각하게 맞았습니다. 내 프로젝트는 종종 여러 바이트에서 수백 바이트까지 다양한 크기의 블록을 할당하며 때로는 '메모리에서'오류에 직면했습니다. 내 PIC32 장치에는 총 32k의 RAM이 있으며 8192 바이트는 힙에 사용됩니다. 특정 순간에는 5K 이상의 자유 메모리가 있지만, 기본 할당자는 단편화로 인해 약 700 바이트에 불과한 최대 비 배정 메모리 블록을 갖습니다. 이것은 너무 나쁘기 때문에 더 효율적인 솔루션을 찾기로 결정했습니다.

나는 이미 일부 할당자를 알고 있었지만, 그들 모두는 몇 가지 제한 사항이 있습니다 (예 : 블록 크기는 전원 또는 2이어야하며 2에서 시작하지 않고 128 바이트부터 시작)이거나 버그가되었습니다. 전에는 매번 기본 할당 자로 다시 전환해야했습니다.

하지만 이번에는 운이 좋다 : 나는 이것을 발견했다 : http://hempeldesigngroup.com/embedded/stories/memorymanager/

이 메모리 할당자를 시도했을 때, 정확히 5k의 자유 메모리로 동일한 상황에서 3800 바이트 블록이 있습니다! 그것은 나에게 믿기 어려웠고 (700 바이트와 비교), 나는 하드 테스트를 수행했다 : 장치는 30 시간 이상 크게 작동했다. 메모리 누출이없고 모든 것이 작동하는대로 작동합니다. 또한 Freertos 저장소 에서이 할당자를 발견했습니다. http://svnmios.midibox.org/listing.php?repname=svn.mios32&path=%2ftrunk%2ffreertos%2fsource%2fportable%2fmemmang%2f&rev=1041&peg=1041# 그리고이 사실은 umm_malloc의 안정성에 대한 추가 증거입니다. 그래서 나는 완전히 umm_malloc으로 전환했고, 나는 그것에 매우 만족합니다.

방금 조금 변경해야했습니다. Macro UMM_TEST_MAIN이 정의되지 않았을 때 구성이 약간 버그가 많았으므로 GitHub 리포지토리를 만들었습니다 (링크는이 게시물의 맨 위에 있습니다). 이제 사용자 종속 구성은 별도의 파일 UMM_Malloc_cfg.h에 저장됩니다.

이 할당 자에 적용된 알고리즘에는 아직 깊이 얻지 못했지만 알고리즘에 대한 자세한 설명이 있으므로 관심있는 사람은 UMM_Malloc.c 파일의 상단을 볼 수 있습니다. 적어도 "Binning"접근 방식은 덜 프로모션에 큰 이점을 제공해야합니다. http://g.oswego.edu/dl/html/malloc.html

나는 마이크로 컨트롤러를위한 효율적인 메모리 할당자를 위해 필요한 사람이라면 누구나 적어도 이것을 시도해야한다고 생각합니다.

내가 이것을 물었을 때 이후로 얼마 였지만, 나의 최종 해결책은 Loki의 Smallobjectallocator를 사용하는 것이 었습니다. 모든 OS 호출을 제거하고 임베디드 장치 용 LUA 엔진의 성능을 향상 시켰습니다. 매우 멋지고 단순하며 약 5 분 분량의 작업!

부터 버전 5.1, 루아 허용했습니다 맞춤 할당 자 언제 설정해야합니다 새로운 상태 만들기.

나는 또한 오래된 스레드이지만 이것에 추가하고 싶습니다. 임베디드 애플리케이션에서 애플리케이션에 대한 메모리 사용량을 분석하고 다양한 크기의 최대 메모리 할당을 제시 할 수있는 경우 일반적으로 가장 빠른 유형의 할당 원은 메모리 풀을 사용하는 것입니다. 임베디드 앱에서는 실행 시간 동안 필요한 모든 할당 크기를 결정할 수 있습니다. 이 작업을 수행 할 수 있다면 힙 조각화를 완전히 제거하고 매우 빠른 할당을 가질 수 있습니다. 이러한 구현에는 대부분의 구현에는 오버플로 풀이있어 특별한 경우에 정기적 인 malloc을 수행 할 수 있습니다.

나는 '바이너리 버디'시스템을 사용하여 VXWorks에서 좋은 효과를 냈습니다. 기본적으로, 당신은 요청을 보유하기 위해 두 개의 크기의 블록의 가장 작은 전력을 얻기 위해 블록을 반으로 자르면서 더미를 부분적으로 나누고, 블록이 풀리면 트리를 통과하여 블록을 다시 합쳐서 조각화를 완화 할 수 있습니다. Google 검색은 필요한 모든 정보를 설정해야합니다.

나는 힙 조각 모음을 수행하고 메모리를 재사용할 수 있도록 고안된tinymem이라는 C 메모리 할당자를 작성 중입니다.확인 해봐:

https://github.com/vitiral/tinymem

메모:이 프로젝트는 Rust 구현 작업을 위해 중단되었습니다.

https://github.com/vitiral/defrag-rs

또한 이전에는 umm_malloc에 ​​대해 들어본 적이 없습니다.불행하게도 조각화를 처리할 수는 없는 것 같지만 확실히 유용해 보입니다.확인해 봐야 겠습니다.

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