Os problemas de utilizar e reutilizar muitos objetos na dimensão variar um aplicativo pode causar a fragmentação do heap que pode abrandar a velocidade do processo. Este artigo usa um objeto fábrica, para fazer e reciclar objectos com efeitos mínimos fragmentação.
Um dos padrões do clássico livro "Design Patterns; Elementos da reutilizável Object-Oriented Software" é o método fábrica, onde os objetos são criados recentemente e eu tive que usar isso. O motivo? Um problema na memória fragmentação utilizando um sistema de simulação de um grande número de objetos hold numéricos para matrizes. Havia vários tipos array numérico, em tamanhos variando de 1500 x 1 para 5000 x 10 ou números inteiros ou duplos. Estas foram utilizadas em uma simulação de um cálculo financeiro durante um período de dois anos, gerando dados sobre cada um dos 472 dias a partir da simulação de dados históricos. Em cada dia, foi lido em dados de um banco de dados, processados e, em seguida, guardado fora.Apesar dos extensos testes de fuga, o software será executado somente por um número de dias antes de simulado o eating up do arquivo de troca do Windows. Memória vazamentos foram cuidadosamente monitorado para baixo e eliminado, mas o meu cabelo estava ainda em perigo. O aplicativo não iria correr por mais tempo do que cerca de 30 dias antes ele havia simulado cometidos ao longo de metade do NT-pager este arquivo em um sistema 512 MB RAM! Fechar inquérito revelou que em cada dia em que ela foi executada, a memória atribuída cresceu de 5M para cerca de 80Mb, em seguida, voltar a encolher cerca de 5M novamente. Face a esta situação, e não um problema com a jogar com 512Mb, mas olhando o Win NT Task Manager mostraram um aumento da quantidade de memória cometido.
FRAGMENTAÇÃO
O problema era simples, era a culpa Escombreira fragmentação. Isso ocorre quando vários objetos são criados e destruídos, em seguida, repetidamente. Como cada objeto é criado, ele consome a memória do heap. Se os objectos foram criados e, em seguida, destruídos por ordem inversa ela provavelmente não iria acontecer como todos os libertou memória poderia ser juntados em um grande bloco. Mas em qualquer sistema com um grande número de objetos a fim de criação e destruição nunca será simétrico-meu app pode facilmente ter até 50.000 objectos em memória ao mesmo tempo. Assim, quando um objeto é destruído, um ponteiro para a memória bloco liberado é adicionado a uma lista de blocos livres.Quando outros pedidos são feitos de memória, o Windows tenta alocar os pedidos fora da primeira lista libertados. Fragmentação acontece quando um grande bloco como 1Mb tenha sido solicitada, e posteriormente libertadas, seguido de um pedido de um menor bloqueio. Isto é retirado do primeiro bloco sobre o livre-list que pode muito bem ser o 1Mb, o que deixa apenas 900Kb livre. Em seguida, um outro pedido de um grande bloco 1Mb surge, ela não pode ser satisfeita a partir da lista livre e assim ele é retirado do heap. Se a criação / destruição ciclo acontece algumas vezes os grandes blocos sobre o heap são cortadas em pequenos pedaços; a RAM física é substituída e com esgotado virtual ram. Gerenciamento de memória do Windows heap (e Delphi) é bastante inteligente, é preciso muito para chegar a este fragmento. Mas sob a pressão implacável de um grande número de objetos a serem criados e destruídos, o gerenciador de memória, gradualmente caverna polegadas
Quando o Windows é executado fora de ram livre, ele começa swapping páginas de carneiro e de desempenho para o disco tem um nariz mergulhar. Seu aplicativo pode ser galopante felizmente, ao longo de 100% da CPU até swapping inicia. Ela então se torna um funeral março rastreamento talvez em 7.10% ao longo do CPU, tendo eternamente a correr. Desastre!
Microsoft ter colocado um grande esforço de tornar o gerenciador de memória tão eficiente quanto possível. Por exemplo, sob SPD, existe um processo de duas fases e reservando cometer memória. Se seu aplicativo requer 100Mb, que é reservado quando o aplicativo é carregado. Mas só quando a memória é acessada são as páginas de reserva cometido. Se quiser saber mais do que você jamais irá possivelmente precisa de saber sobre este e outros tópicos, eu recomendo o livro Inside NT, publicado pela Microsoft Press, mas buscar o David Salomão, que é a versão posterior edição, não a primeira edição Helen Custer.
FÁBRICA DE MODELO
Então eu não precisava de uma fragmentação forma de criar muitos objetos, usando-os, atirando-as para longe e depois fazer tudo de novo sem janelas esgotar-se de memória virtual. Após ter lido recentemente o livro Pattern eu pensei por que não utilizar uma fábrica, ou seja, uma fábrica objeto que cria objetos de uma determinada classe. Eu fui um melhor e, em seguida, tornou amigo do ambiente, de forma que ele chegue ao reciclar todos os seus objectos manufacturados em vez de destruí-los e sem os problemas associados fragmentar. O ouro sobre azul para fazer a fábrica foi capaz de expandir a sua capacidade sem perda da velocidade de acesso.
Ao invés de ter uma fábrica classe para todos os tipos de classe, tomei a abordagem simples passando o objeto da classe para a fábrica como uma fábrica criação parâmetro. Quando a fábrica é criada você quer especificar a classe de objetos que podem fazer e à capacidade de armazenamento inicial da fábrica. Este tamanho pode ser alterado para cima, invocando o método GrowFactory. Sugiro-lhe que só em casos excepcionais este convite (!) As circunstâncias.
O link para voltar à fábrica a partir de cada objeto é necessária, para que todos os "objetos feitos fábrica" (FMO) devem descender de uma classe TFactoryObject vez de Tobject. Isso adiciona uma referência fábrica, que é "carimbada" em todas as QOM, para que saiba qual o objeto a ser usado para reciclar fábrica propriamente dita.
Em vez de criar um objeto a partir de seu aplicativo solicita uma chamada à adequado fábrica por sua RequestObj método que retorna um objeto regressar tclass e convertê-la a você o direito classe usando 'como'. Finalmente, quando você tiver terminado de utilizar o objeto que você acabou de chamar seu método RecycleSelf. Qualquer criação ou destruição excepção das fábricas próprias.
COMO FUNCIONA
Quando a fábrica é criada, todos os objetos são criados fisicamente em um bloco contíguo de carneiro. Um tlist (fblocklist) objeto guarda o endereço de cada um destes blocos. Cada vez que você cresça a fábrica, um novo bloco é criado e adicionado a esta lista. O método AddObjects cria o número especificado de objetos utilizando o aríete do bloco. Se você escrever código como este estar conscientes de que só a fazer uma tobject (endereço) não é suficiente para criar o objeto. Proteja-se chamar ObjectClass.InitInstance (endereço) para transformá-lo em um 'bom' objeto. InitInstance apaga tudo do zero, etc, mas nada é mais importante que cria o VMT.
A fábrica também contém um outro tlist (ffreelist), que detém o endereço de todos os objetos não utilizados.
Todos os burros de trabalho da fábrica de enchimento é feito no método AddObjects privado. Para cada objeto criado no bloco, este converte o ponteiro ptr em um objeto, utilizando FactoryObject como a classe do objeto criado. Este deve ser um descendente de TfactoryObject. Obj detém o objeto de referência e links da fábrica até o objeto fabricado. ptr então é incrementado para apontar para o próximo objeto do bloco, acrescentando fsize.
Para obter um objeto que se chama Request_Obj r código que aparece a referência ao largo do final do ffreelist e devolve-lo como o primeiro objeto solicitado. A reciclagem é o inverso; que empurra o objeto reciclado referência para o final de ffreelist. Um aspecto a ter em mente. Quando uma fábrica feita objeto está em uso, a fábrica não tem qualquer referência a ele, embora a memória ocupada pelo objeto está contido dentro da fábrica!
Substituindo criar e destruir
Usando a fábrica exige que você use objetos fabricados de maneira um pouco diferente do normal. Você deixou de criar ou libertá-las expressamente, em vez disso que você acabou de pedir a fábrica relevantes para o objeto. A menos que a fábrica está vazia semper isso irá funcionar. Você tem que modificar o código de inicialização do construtor e de rescisão código no destrutor rotinas. Existem duas abordagens.
1) Se o objeto tem uma simples criar construtor sem parâmetros, você poderá renomeá-lo ao processo init; sobrepor herdou criar e remover quaisquer chamadas. A fábrica semper chama um método Init quando algum objeto for solicitado. Por padrão esta não faz nada, mas você pode substituir esse seu modo Init será chamado automaticamente a cada objeto solicitado à fábrica.
2) Se a sua criação original tem parâmetros, mude o nome para algo como inicializar e remover herdadas chamadas etc. Após o objeto é solicitada a chamada inicializar rotina, por exemplo, MyRoutine.Initialise (...)
Se o objeto tem destrutor código, mude o nome ao procedimento Feito; sobrepor a fim de que ele é chamado automaticamente quando o objeto é reciclado. Feito Init e são semelhantes para criar / destruir, mas sem a bagagem de construção ou o mecanismo de destruição.
Como uma pequena digressão, eu entendo que há argumentos a favor da Delphi no mundo sobre uma parte ou duas criação parte Uma parte é quando o construtor tem parâmetros e completamente cria o objeto. Na parte dois abordagem, o construtor só cria um objeto em branco que depois é lançado por um método mais tarde. A fábrica abordagem Acho que está firmemente nas duas partes acampamento ..
Quando a fábrica é destruída, todas as alocado memória blocos são libertadas. Antes disso, a fábrica verifica que o número de objetos na freelist jogos da capacidade. Se você esqueceu a reciclar todos os seus objetos remanescentes, que irá levantar uma exceção.
COMPARAÇÃO DO PROGRAMA
Isto mostra os benefícios das fábricas .. No meu trabalho app tinha muitos tamanhos diferentes de objetos em quantidades diferentes, mas uma linha 15000 programa não iria ser exactamente publicável. Após um pouco de tentativa e erro eu vim para cima com um curto programa que possa mostrar fragmentação. No entanto, isto depende do tamanho dos diferentes objetos, quantas existem, disponíveis ram e por quanto tempo ele é executado. Além disso, a fragmentação parece ocorrer mais rapidamente NT4.0 no máximo 98, que sugere que talvez 98 tem um melhor gestor de memória. Quando é executado ele cria e destrói um grande número de objetos várias vezes para o número especificado de dias. Também faz exatamente a mesma coisa usando uma fábrica. Cada dia é oportuno, e ambos os conjuntos de tempos plotados usando Tchart.Eu usei três tipos de objectos, todos os descendentes de tTestobj qual descende de Tfactoryobject. Pequenos objetos 2K estão no tamanho, médias e grandes são 40k são 800k, mas estes tamanhos são definidos pelas constants e pode facilmente alterados. O programa demostrativo aloca 100Mb para o normal e outro objetos 100Mb para a fábrica. Ambas contêm o mesmo número de objetos-dividida igualmente entre as três dimensões por tipos de objeto forma que há 17406 objetos pequenos, 873 médias e 43 grandes. No processo objeto criação TimeOneDay aleatoriamente estes são criados e adicionados à lista. Ao final do dia em que são libertadas, eo processo repetido no dia seguinte.O mesmo é feito usando três fábricas com todos os objectos manufacturados adicionado a uma lista factorydata. Em um P2 400 com 256Mb correr durante 100 dias, houve um ligeiro aumento no tempo de ambas as fábricas e da criação objeto normal. Fora do normal Pronunciando criação confirmaram esta suspeita, o aumento foi muito menor ao longo de um dia correr 1000 usando fábricas contra 100 dias, em ambos os testes normais e de fábrica. Eu suponho que isto era causado pelo aumento da página swapping devido à fragmentação que afectam ambos os processos. Algumas outras combinações de tamanho e número de objetos sob o Windows 98 não mostrou qualquer fragmentaçãoEu implementado inicialmente utilizando um presente para ambas tlist testdata e factorydata e mudou-los mais tarde, quando eu percebi que a adição repetitiva e libertando 18.000 ponteiros também foi acrescentando à fragmentação heap. Eu não estou defendendo afundamento tstringlists completamente em seu código-eles são muito úteis (como são tlists), mas se tiver de manipular um grande número de itens, pode ser melhor para usar as suas próprias estruturas lista. Se você quiser usar ou tlist Tstringlist para este efeito, provavelmente o seu melhor para encher completamente a estrutura com ponteiros nula, de modo que count = utilização da capacidade e um inteiro para manter o índice do último ponteiro.
Este aplicativo também confirmou que a fábrica código é muito rápido na atribuição e cancelamento-tipicamente 30 ms para 18000 objetos ao invés do que 870 ms normal criação / deleção tomou.
------------------------------------------------
Tgis artigo apareceu originalmente na revista para desenvolvedores Delphi. Sources.zip

Delicious
Digg
Google
Yahoo