Pergunta

Eu tenho uma rosca única, aplicativo embutido que aloca e desaloca lotes e lotes de pequenos blocos (32-64b). O cenário perfeito para um alocador de base cache. E embora eu poderia tentar escrever um que provavelmente vai ser um desperdício de tempo, e não tão bem testado e afinado como alguma solução que já tem sido na linha de frente.

Então, o que seria a melhor alocador eu poderia usar para esse cenário?

Nota:. Eu estou usando uma máquina virtual Lua no sistema (que é o culpado de 80 +% das dotações), então não posso trivialmente refatorar meu código para alocações uso de pilha para aumentar o desempenho de alocação

Foi útil?

Solução

Eu fiz alguma pesquisa sobre este tema recentemente, como tivemos um problema com a fragmentação da memória. No final, decidimos ficar com a implementação da GNU libc, e adicionar alguns pools de memória em nível de aplicativo, se necessário. Havia outros alocadores que tiveram melhor comportamento fragmentação, mas não fomos suficientemente confortável com eles substituir malloc globalmente. GNU de tem o benefício de uma longa história por trás dele.

No seu caso, parece justificado; supondo que você não pode corrigir o VM, essas pequenas alocações são muito desperdício. Eu não sei o que o seu ambiente todo é, mas você pode considerar envolvendo as chamadas para malloc / realloc / livre apenas na VM de modo que você pode passá-lo para um manipulador projetado para pequenas piscinas.

Outras dicas

Em um projeto passado em C em que trabalhei, descemos a estrada de implementar as nossas próprias rotinas de gerenciamento de memória para um ran biblioteca em uma ampla gama de plataformas, incluindo sistemas embarcados. A biblioteca também alocada e liberada um grande número de pequenos buffers. Ele correu relativamente bem e não ter uma grande quantidade de código para implementar. Posso dar-lhe um pouco de fundo em que a implementação no caso de você querer desenvolver algo a si mesmo.

A implementação básica incluiu um conjunto de rotinas que conseguiram buffers de um tamanho definido. As rotinas foram utilizadas como invólucros em torno malloc () e free (). Nós usamos essas rotinas para gerenciar alocação de estruturas que freqüentemente usados ??e também para gerenciar buffers genéricos de tamanhos definidos. A estrutura foi usada para descrever cada tipo de tampão a ser gerido. Quando um buffer de um tipo específico foi alocado, estaríamos malloc () a memória em blocos (se uma lista de buffers livres estava vazio). IE, se estivéssemos gestão 10 buffers de bytes, podemos fazer uma única malloc () que continha espaço para 100 desses buffers de reduzir a fragmentação eo número de mallocs subjacentes necessários.

Na parte da frente de cada tampão seria um ponteiro que seria utilizada para encadear os tampões em uma lista livre. Quando os 100 tampões foram atribuídas, cada tampão iria ser encadeados na lista livre. Quando o tampão foi em uso, o ponteiro seria definida como nulo. Nós também manteve uma lista dos "blocos" de buffers, para que pudéssemos fazer uma limpeza simples chamando free () em cada um dos buffers malloc reais.

Para o gerenciamento de tamanhos de buffer dinâmico, nós também adicionamos uma variável size_t no início de cada buffer dizer o tamanho do buffer. Este foi então usado para identificar quais bloco tampão para colocar a parte de trás em tampão em que foi libertado. Tivemos rotinas de reposição para malloc () e free () que fez a aritmética de ponteiro para obter o tamanho do buffer e, em seguida, colocar o tampão na lista livre. Nós também tinha um limite de quão grande de buffers conseguimos. Buffers maiores do que esse limite foram simplesmente malloc e passado para o usuário. Para as estruturas que nós gerenciados, nós criamos rotinas de mensagens publicitárias para a alocação e liberação das estruturas específicas.

Finalmente, nós também evoluiu o sistema para incluir a coleta de lixo quando solicitado pelo usuário para limpar a memória não utilizada. Uma vez que tínhamos controle sobre todo o sistema, houve várias otimizações que fomos capazes de fazer ao longo do tempo para aumentar o desempenho do sistema. Como eu mencionei, não funcionou muito bem.

Estou um pouco atrasado para a festa, mas eu só quero compartilhar alocador de memória muito eficiente para sistemas embarcados que eu encontrei recentemente e testado: https://github.com/dimonomid/umm_malloc

Esta é uma biblioteca de gerenciamento de memória especificamente projetado para trabalhar com o ARM7, pessoalmente, eu usá-lo no dispositivo PIC32, mas deve funcionar em qualquer dispositivo de 16 e 8-bit (eu tenho planos de testar em em 16-bit PIC24 , mas eu não testei ainda)

Eu estava seriamente espancado por fragmentação com alocador padrão: o meu projeto, muitas vezes aloca blocos de vários tamanhos, a partir de vários bytes para várias centenas de bytes, e às vezes eu enfrentei 'falta de memória' de erro. Meu dispositivo PIC32 tem 32K total de RAM, e 8192 bytes é usado para heap. No momento em particular, há mais de 5K de memória livre, mas alocador padrão tem bloco de memória máxima não fragmentado apenas de cerca de 700 bytes, por causa da fragmentação. Isso é muito ruim, então eu decidi procurar uma solução mais eficiente.

Eu já estava ciente de algumas allocators, mas todos eles tem algumas limitações (como o tamanho do bloco deve ser uma potência ou 2, e partindo não 2, mas de, digamos, 128 bytes), ou era apenas buggy. Toda vez antes, eu tive que voltar para o alocador padrão.

Mas desta vez, eu tenho sorte: Eu encontrei este: http: // hempeldesigngroup .com / embedded / histórias / memorymanager /

Quando eu tentei este alocador de memória, exatamente na mesma situação com 5K de memória livre, ele tem mais de 3800 bytes bloco! Era tão inacreditável para mim (em comparação com 700 bytes), e eu realizado o teste mais difícil: aparelho funcionou muito mais do que 30 horas. Sem vazamentos de memória, tudo funciona como deveria funcionar. Eu também encontrei este alocador nas FreeRTOS repositório: http://svnmios.midibox.org/listing.php?repname=svn.mios32&path=%2Ftrunk%2FFreeRTOS%2FSource%2Fportable%2FMemMang%2F&rev=1041&peg=1041# , e este fato é uma evidência adicional de estabilidade do umm_malloc. Então eu mudei completamente a umm_malloc, e eu estou muito feliz com ele.

Eu apenas tive que mudar um pouco: configuração foi um pouco buggy quando UMM_TEST_MAIN macro não está definida, por isso, eu criei o repositório github (o link está no topo deste post). Agora, depende da configuração do usuário é armazenado em arquivo separado umm_malloc_cfg.h

Eu ainda não tenho profundamente nos algoritmos aplicada neste alocador, mas tem muito detalhada explicação dos algoritmos, assim qualquer um que esteja interessado pode olhar para o topo da umm_malloc.c arquivo. Pelo menos, "binning" abordagem deve dar grande benefício em menos fragmentação: http: // g .oswego.edu / dl / html / malloc.html

Eu acredito que qualquer um que precisa de alocador de memória eficiente para microcontroladores, deve pelo menos tentar este.

Apesar de sua sido algum tempo desde que eu perguntei isso, a minha solução final era usar SmallObjectAllocator de Loki que funcionam muito bem. Got livrar fora todas as chamadas de sistema operacional e melhorou o desempenho do meu motor Lua para dispositivos embarcados. Muito agradável e simples, e apenas cerca de 5 minutos no valor do trabalho!

Eu tinha acabado também gostaria de acrescentar a esta, mesmo que seja uma discussão antiga. Em um aplicativo incorporado se você pode analisar seu uso de memória para a sua aplicação e chegar a um número máximo de alocação de memória dos tamanhos variados geralmente o tipo mais rápido de alocador é um usando pools de memória. Em nossos aplicativos embutidos podemos determinar todos os tamanhos de alocação que nunca vai ser necessárias durante a execução. Se você puder fazer isso, você pode eliminar completamente a fragmentação da heap e têm atribuições muito rápidas. A maioria destas implementações têm uma piscina estouro que vai fazer um malloc regular para os casos especiais que, esperamos, será muito poucos e entre se você fez o seu direito análise.

Eu tenho usado o sistema 'buddy binário' com bons resultados sob vxworks. Basicamente, você parte para fora sua pilha cortando blocos ao meio para obter o menor poder de dois blocos de tamanho para manter o seu pedido, e quando os blocos são libertados, você pode fazer um passe para cima da árvore de blocos de mesclagem de volta junto à fragmentação mitigar. Uma busca no Google deve transformar-se todas as informações que você precisa.

Eu estou escrevendo um alocador de memória C chamado tinymem que se destina a ser capaz de desfragmentar o montão, e memória re-uso. Confira:

https://github.com/vitiral/tinymem

Nota: este projecto foi interrompido para o trabalho sobre a implementação de ferrugem:

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

Além disso, eu não tinha ouvido falar de umm_malloc antes. Infelizmente, isso não parece ser capaz de lidar com a fragmentação, mas ele definitivamente parece útil. Vou ter que verificá-la.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top