Ottimizzare l'utilizzo della memoria del programma Delphi

Quando si scrivono applicazioni a esecuzione prolungata, il tipo di programmi che trascorrerà gran parte della giornata è ridotto a icona sulla barra delle applicazioni o area di notifica, può diventare importante non lasciare che il programma "scappi" con l'utilizzo della memoria.

Le due colonne più a destra indicano l'utilizzo della CPU (tempo) e l'utilizzo della memoria. Se un processo influisce gravemente su uno di questi, il sistema rallenterà.

Il tipo di cose che influisce frequentemente sull'utilizzo della CPU è un programma in loop (chiedi a qualsiasi programmatore che ha dimenticato di inserire un'istruzione "read next" in un ciclo di elaborazione dei file). Questi tipi di problemi vengono generalmente corretti abbastanza facilmente.

L'uso della memoria, d'altra parte, non è sempre evidente e deve essere gestito più che corretto. Si supponga, ad esempio, che sia in esecuzione un programma del tipo di acquisizione.

Questo programma viene utilizzato tutto il giorno, possibilmente per l'acquisizione telefonica presso un help desk o per qualche altro motivo. Non ha senso spegnerlo ogni venti minuti e poi riavviarlo. Sarà usato per tutto il giorno, anche se a intervalli rari.

instagram viewer

Se quel programma si basa su una pesante elaborazione interna o ha molte opere d'arte nelle sue forme, prima o poi le sue utilizzo della memoria crescerà, lasciando meno memoria per altri processi più frequenti, aumentando l'attività di paginazione e infine rallentando il computer.

Diciamo che progetterai un programma con il modulo principale e due moduli (modali) aggiuntivi. In genere, a seconda della versione di Delphi, Delphi inserisce i moduli in unità di progetto (File DPR) e includerà una riga per creare tutti i moduli all'avvio dell'applicazione (Applicazione. CreateForm (...)

Le linee incluse nell'unità di progetto sono progettate da Delphi e sono perfette per le persone che non hanno familiarità con Delphi o che hanno appena iniziato a usarlo. È conveniente e utile. Significa anche che TUTTI i moduli verranno creati all'avvio del programma e NON quando sono necessari.

A seconda di cosa tratta il tuo progetto e delle funzionalità che hai implementato, un modulo può usare molta memoria, quindi i moduli (o in generale: gli oggetti) dovrebbero essere creati solo quando necessari e distrutti (liberati) non appena non lo sono più necessario.

Entrambi, "DialogForm" e "OccasionalForm" devono essere rimossi dall'elenco di "Creazione automatica dei moduli" e spostati nell'elenco "Moduli disponibili".

Si noti che la strategia descritta qui si basa sul presupposto che il programma in questione sia un programma di tipo "acquisizione" in tempo reale. Tuttavia, può essere facilmente adattato per processi di tipo batch.

Delphi ha cercato di minimizzare questo e ha una propria architettura di gestione della memoria che utilizza blocchi molto più piccoli ma questo è praticamente inutile in ambiente Windows perché l'allocazione della memoria dipende in ultima analisi dal sistema operativo.

Dopo che Windows ha assegnato un blocco di memoria a un processo e tale processo libera il 99,9% della memoria, Windows percepirà comunque l'intero blocco in uso, anche se in realtà è presente solo un byte del blocco Usato. La buona notizia è che Windows fornisce un meccanismo per risolvere questo problema. La shell ci fornisce un'API chiamata SetProcessWorkingSetSize. Ecco la firma:

Per definizione, la funzione SetProcessWorkingSetSize imposta le dimensioni minime e massime del set di lavoro per il processo specificato.

Questa API ha lo scopo di consentire un'impostazione di basso livello dei limiti minimo e massimo della memoria per lo spazio di utilizzo della memoria del processo. Tuttavia, ha una piccola stranezza che è molto fortunata.

Se entrambi i valori minimo e massimo sono impostati su $ FFFFFFFF, l'API taglierà temporaneamente la dimensione impostata su 0, scambiandola fuori memoria e immediatamente rimbalza di nuovo nella RAM, avrà la minima quantità di memoria allocata ad esso (tutto ciò accade entro un paio di nanosecondi, quindi per l'utente dovrebbe essere impercettibile).

Una chiamata a questa API verrà effettuata solo a intervalli prestabiliti, non in modo continuo, quindi non dovrebbe esserci alcun impatto sulle prestazioni.

Ora, controlla periodicamente l'ultimo conteggio dei segni di spunta rispetto a "Adesso" e se la differenza tra i due è maggiore del periodo considerato inattivo, ritaglia la memoria.

Ora decidi dopo quale periodo di tempo ritieni che il programma sia inattivo. Nel mio caso abbiamo deciso due minuti, ma puoi scegliere qualsiasi periodo desideri in base alle circostanze.

Adattare questo metodo per lunghi tempi di elaborazione o processi batch è abbastanza semplice. Normalmente avrai una buona idea di dove inizierà un lungo processo (es. Inizio di un ciclo di lettura attraverso milioni di record del database) e dove finirà (fine del ciclo di lettura del database).

Disattiva semplicemente il timer all'inizio del processo e riattivalo alla fine del processo.