Pergunta

Atualmente estou trabalhando em um projeto para processamento de imagens médicas, que precisa de uma enorme quantidade de memória. Existe algo que eu possa fazer para evitar a fragmentação de pilha e para acelerar o acesso de dados de imagem que já foi carregado na memória?

O aplicativo foi escrito em C ++ e é executado no Windows XP.

EDIT: O aplicativo faz algum pré-processamento com os dados de imagem, como a reformatação, calculando olhar-up-tables, extraindo sub imagens de interesse ... As necessidades de aplicação de cerca de 2 GB de RAM durante o processamento, dos quais cerca de 1,5 GB podem ser utilizados para os dados de imagem.

Foi útil?

Solução

Se você está fazendo o processamento de imagem médica é provável que você está alocando grandes blocos de cada vez (512x512, 2-byte por pixel imagens). Fragmentação vai morder você se você alocar objetos menores entre as alocações de buffers de imagem.

Escrevendo um alocador de costume não é necessariamente difícil para este caso de uso particular. Você pode usar o alocador padrão C ++ para o seu objeto de imagem, mas para o pixel de buffer você pode usar alocação personalizado que é tudo gerenciado dentro do seu objeto de imagem. Aqui está um esboço rápido e sujo:

  • Use uma matriz estática de estruturas, cada um struct tem:
    • Um pedaço sólido de memória que pode armazenar imagens N - chunking fragmentação vai ajudar a controlar - tentar um N inicial de 5 ou assim
    • Um arranjo paralelo de bools indicando se a imagem correspondente é em uso
  • Para alocar, procurar a matriz para um tampão de vazio e definir a sua bandeira
    • Se nenhum encontrado, acrescentar uma nova estrutura para o fim do array
  • Para desaloque, encontrar o tampão correspondente na matriz (s) e apagar o indicador de booleano

Esta é apenas uma idéia simples, com muito espaço para variação. O truque principal é evitar libertar e reafectar os buffers de pixel da imagem.

Outras dicas

Há respostas, mas é difícil de ser geral sem conhecer os detalhes do problema.

Estou assumindo 32-bit Windows XP.

Tente evitar a necessidade de 100s de MB de memória contígua, se você é azarado, algumas dlls aleatórios irá carregar-se em pontos inconventient através de seu espaço de endereços disponíveis rapidamente cortar áreas muito grandes de memória contígua. Dependendo do que APIs você precisa, isso pode ser bastante difícil de evitar. Ele pode ser bastante surpreendente como apenas alocar um par de 400MB blocos de memória, além de alguns uso de memória 'normal' pode deixá-lo sem ter para onde alocar um 'pequeno' bloco final 40MB.

Por outro lado, fazer pedaços do tamanho razoáveis ??preallocate de cada vez. Da ordem de 10MB ou assim é um tamanho bom bloco de compromisso. Se você pode gerenciar a particionar seus dados para este tipo de pedaços do tamanho, você vai ser capaz de preencher o espaço de endereço razoavelmente eficiente.

Se você ainda vai ficar sem espaço de endereço, você está indo a necessidade de ser capaz de blocos de páginas dentro e para fora com base em algum tipo de cache algoritmo. Escolhendo os blocos certos para página fora vai depender muito do seu algortihm processamento e terá uma análise cuidadosa.

Escolher onde página as coisas para outra decisão. Você pode optar por apenas escrevê-los para arquivos temporários. Você também pode investigar Address Windowing extenstions API da Microsoft. Em ambos os casos é preciso ter cuidado na sua concepção aplicativo para limpar todos os ponteiros que estão apontando para algo que está prestes a ser paginada de outra forma muito ruim as coisas (tm) vai acontecer.

Boa sorte!

Se você estiver indo para ser realizar operações em uma grande matriz de imagem, você pode querer considerar uma técnica chamada "ladrilhos". A idéia é geralmente para carregar a imagem na memória para que o mesmo bloco contíguo de bytes não contêm pixels em uma linha, mas sim de um quadrado no espaço 2D. A lógica por trás disso é que você faria mais operações que estão mais próximos uns aos outros em 2D em vez de uma linha de varredura.

Isto não vai reduzir o uso de memória, mas pode ter um enorme impacto na página troca e desempenho.

Sem muito mais informações sobre o problema (por exemplo idioma), uma coisa que você pode fazer é evitar o churn alocação através da reutilização de alocações e não alocar, operar e livre. Alocador como dlmalloc alças fragmentação melhor do que montes Win32.

O que você vai estar batendo aqui é limite de intervalo de endereço virtual, que com 32b do Windows dá-lhe, no máximo, 2 GB. Você deve estar também ciente de que usando uma API gráfica como DirectX ou OpenGL usará extensas porções daqueles 2 GB para o buffer de quadros, texturas e dados semelhantes.

1,5-2 GB para uma aplicação 32b é bastante difícil de alcançar. A maneira mais elegante de fazer isso é usar 64b OS e aplicação 64b. Mesmo com 64b OS e aplicação 32b pode ser um pouco viável, contanto que você usar LARGE_ADDRESS_AWARE.

No entanto, como você precisa de dados de imagem loja, você também pode ser capaz de contornar isso usando Mapeamento de arquivo como um armazenamento de memória - isso pode ser feito de tal forma que você tem uma memória comprometida e acessível, mas não usando os endereços virtuais em tudo .

supondo aqui que você quis dizer evitar a fragmentação e não evitar a desfragmentação . Também supondo que você está trabalhando com uma linguagem não conseguiu (c ou C ++ provavelmente). Gostaria de sugerir que você alocar grandes blocos de memória e depois servir alocações de heap de blocos de memória alocados. Este pool de memória contém porque grandes blocos de memória é lessely propenso a fragmentação. Para resumir, você deve implementar um alocador de memória personalizado.

Veja algumas ideias gerais sobre esta aqui .

I gues você está usando algo não gerenciado, porque em plataformas gerenciados do sistema (coletor de lixo) cuida de fragmentação.

Para C / C ++, você pode usar algum outro alocador, do que o padrão. (Havia alrady alguns tópicos sobre allocators sobre stackowerflow).

Além disso, você pode criar seu próprio armazenamento de dados. Por exemplo, no projeto que estou trabalhando atualmente, temos um armazenamento personalizado (pool) para bitmaps (nós armazená-los em um grande pedaço contigous de memória), porque temos um monte deles, e nós manter o controle de pilha fragmentação e desfragmentar-lo quando a fragmentação é grande.

Você pode precisar para implementar o gerenciamento de memória manual. É os dados da imagem de longa vida? Se não, então você pode usar o padrão usado pelo Apache servidor web: alocar grandes quantidades de memória e envolvê-los em pools de memória. Passar essas piscinas como o último argumento em funções, para que possam utilizar a piscina para satisfazer a necessidade de alocar a memória temporária. Uma vez que a cadeia de chamada for concluída, toda a memória na piscina pode deve ser não utilizado, assim você pode esfregar a área de memória e usado novamente. Alocações são rápidos, uma vez que só significar a adição de um valor para um ponteiro. Desalocação é muito rápido, uma vez que você irá liberar muito grandes blocos de memória de uma vez.

Se o seu aplicativo é multithreaded, pode ser necessário para armazenar a piscina de armazenamento local de segmento, para evitar a comunicação sobrecarga cross-fio.

Se você pode isolar exatamente aqueles lugares onde é provável que você alocar grandes blocos, você pode (no Windows) diretamente chamar VirtualAlloc em vez de ir através do gerenciador de memória. Isso irá evitar a fragmentação dentro do gerenciador de memória normal.

Esta é uma solução fácil e não requer que você use um gerenciador de memória personalizado.

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