2010-06-24 24 views
5

Hei community,Tempo per eliminare i puntatori

Ho una piccola domanda relativa alla cancellazione dei puntatori.

Sto lavorando con matrici da puntatore a puntatore di Dimensione 1024x1024. Dal momento che li sto creando dinamicamente, elimino lo spazio allocato per loro alla fine del programma. Ma fare questo nel solito giro costa un sacco di tempo - ho misurato circa 2 secondi usando il clock rate del processore. E 2 secondi è ENORME quando il programma gira solo 15 secondi - più: la funzione che usa questi puntatori assegnati viene chiamata più di una volta sola ....

Ecco il pezzo misurato time-critical del Codice tra cui la misura:

time=clock(); 
for(i=0;i<xSize;i++){   //xSize is dynamic, but 1024 for the measurement 
    delete [] inDaten[i]; 
    delete [] inDaten2[i]; 
    delete [] copy[i]; 
} 
delete inDaten; delete inDaten2; delete copy; 
time=clock()-time; 
    time/=CLOCKS_PER_SEC; 

sta cancellando le indicazioni SEMPRE così a lungo? O sto semplicemente facendo le cose nel modo sbagliato?

Spero che qualcuno qui mi possa aiutare con quello. Dal momento che sto ottimizzando un programma abbastanza complesso per funzionare più velocemente, non posso usare quei 2 pezzi di codice. È solo un modo TROPPO lento rispetto a tutte le altre parti. Ma devo ancora essere in grado di implementare questo codice in modo dinamico. Gli SmartPointer potrebbero essere utili, ma se ho capito bene, hanno anche bisogno di tempo per cancellarsi - solo in un momento diverso ...

Grazie per le vostre risposte!

Baradrist

EDIT: ho appena scoperto, che misura questi eliminazione-calcoli è piuttosto lento perché non ho compilo in release-mode. Dal momento che il debugger entra in gioco, ho misurato questi numeri (alla fine irreali) che mi hanno fatto venire il mal di testa. Il programma finale viene ottimizzato automaticamente in modo tale da non perdere più tempo nella cancellazione.

In ogni caso: grazie per tutte le risposte utili! Mi hanno dato molte conoscenze extra e cose a cui pensare !!!!

+1

Qual è il tipo di oggetti in 'inDaten',' inDaten2' e 'copy'? Sono solo intarsi o qualcosa del genere, o sono oggetti reali? –

+1

Hai bisogno di allocare dinamicamente tutto? Hai bisogno di così tante * allocazioni separate *? È possibile riscrivere il programma per archiviare i dati in allocazioni meno numerose? – jalf

+0

Sul mio netbook, l'eliminazione di double [] non raggiunge il segno di spunta successivo, quindi o stai correndo con un debugger collegato, oppure qualcosa di costoso sta accadendo nei distruttori degli elementi dell'array. –

risposta

3

delete[] chiamerà anche i distruttori per ogni elemento dell'array che aggiunge tempo a meno che il distruttore non sia banale.

Diverso da quello - sì, l'allocazione dinamica della memoria è relativamente costosa. Se non riesci a tollerarlo, prova ad allocare meno blocchi di dimensioni maggiori o ad andare senza allocazioni dinamiche in roba time-critical.

I puntatori intelligenti non saranno di grande aiuto - faranno la stessa deallocazione all'interno. Non sono per l'accelerazione, ma per la convenienza del design.

1

Se li si elimina alla fine del programma e non importa quando vengono eseguiti i distruttori, è sufficiente lasciare la cancellazione, la memoria verrà rilasciata dal sistema operativo. Altrimenti, prova ad usare le singole istruzioni indirette, cioè senza matrici da puntatore a puntatore. Oltre a ridurre i tempi di cancellazione, questo migliorerà anche la località di riferimento.

+2

Non è garantito che il sistema operativo libererà del tutto la memoria. – Yacoby

+3

@Yacoby: a meno che il sistema operativo stesso non garantisca tale garanzia. Qualunque sistema operativo moderno (desktop). – jalf

+0

Indipendentemente dal fatto che il sistema operativo pulisca o meno la memoria del processo all'uscita, è comunque una cattiva pratica affidarsi a una tale stampella. Meglio utilizzare un allocatore più adatto per la deallocazione veloce e/o riprogettare il codice per minimizzare la deallocazione (senza introdurre perdite, ovviamente). – Void

2

Ecco una discussione interessante "Memory Allocation/Deallocation Bottleneck?"

Allocazione e deallocazione richiedere molto tempo e quindi sono una delle costose operazioni più comuni avete. Questo perché la gestione dell'heap deve occuparsi di un sacco di cose. Di solito ci sono anche più controlli sui blocchi di memoria in modalità di debug. Se avessi lo stesso tempo nella configurazione di rilascio sarei sorpreso, di solito c'è un fattore tra almeno 2. Con un mucchio privato puoi aumentare le cose in modo drammatico.Se si assegnano sempre oggetti della stessa dimensione, un pool di memoria potrebbe essere la migliore alternativa.

0

Provare a creare i propri metodi di allocazione della memoria in modo da ridurre il tempo di distruzione.

Ad esempio, richiedere un blocco di memoria da Os e allocare l'array su di esso in modo da poter liberare l'intero blocco in un'unica operazione.

1

Sembra che il problema sia nella struttura dei dati. Perché hai bisogno di così tante allocazioni dinamiche? Cosa si può fare per ridurre il numero di allocazioni?

Se liberare i puntatori richiede 2 secondi, è probabile che lo richieda almeno altrettanto.

La loro liberazione può essere evitata semplicemente uscendo anticipatamente dal programma. C++ non fornisce garanzie su ciò che accadrà con la memoria allocata, ma probabilmente il tuo sistema operativo lo fa, quindi in termini pratici, potrebbe essere un modo semplice per ridurre di 2 secondi il tempo di esecuzione.

Ma ciò lascia ancora i> 2 secondi per le allocazioni.

La soluzione migliore è provare a strutturare meglio i dati, penso. Puoi mostrarci come è strutturata la matrice al momento?

+0

L'utilizzo di matrici 1-dim consente di risparmiare tempo! Hai ragione riguardo alla struttura. Le matrici contengono scale di grigi di pinture (quindi 1024x1024 ecc.). Ma ancora: l'allocazione è molto più veloce della deallocazione (misurata in base alle esigenze) – Baradrist

0

Grazie MOLTO per tutte le risposte veloci !!! È bello vedere che c'è qualcuno là fuori che aiuta =). Per quanto riguarda il mio problema, mi sembra di dover affrontare questa perdita di tempo, poiché ho bisogno degli array dinamici come matrici temporanee in sottoprogrammi più piccoli che alla fine non vengono eseguiti.

Anyways: again THANKS !! E buona giornata!

Baradrist

+0

L'uso di matrici monodimensionali dovrebbe fare il trucco - grazie! – Baradrist

0

Se gli oggetti hanno indicato nelle matrici hanno distruttori non banali, non c'è molto che si può fare per migliorare in modo significativo runtime senza affrontare quella prima. In caso contrario:

Invece di fare inDaten, inDaten2 and copy array di dimensioni isize di puntatori ad array di dimensioni isize perché non li rendono array di dimensioni isize*isize e invece di affrontare i singoli elementi con: array[i][j] loro indirizzo con array[i*isize+j]. In questo modo è possibile eseguire la pulizia con una chiamata a delete [].

1

non questo dovrebbe essere:

delete [] inDaten; delete [] inDaten2; delete [] copy; 

perché come usato, sono ovviamente array. (Almeno sembrano anche essere, non hai fornito abbastanza contesto).

+0

Sì, dovrebbe essere - già cambiato, ma non modifica i numeri di tempo =). – Baradrist

0

Un ottimizzazione per questo è di allocare memoria in blocchi, allocare singoli puntatori con posizionamento nuovo e alla cancellazione basta eliminare l'intero blocco.

Si dovrà fare attenzione però, poiché questa opzione implicitamente non chiama il distruttore per ogni oggetto allocato con il posizionamento nuovo.

1

Non si dice quanto siano grandi gli oggetti negli array, ma se sono sufficientemente grandi, è possibile che parte della memoria sia stata scambiata e che sia necessario ricollocare (o eventualmente rimappare nuovamente in process space), e questo sta causando il tempo che stai vedendo.

0

Se le allocazioni/deallocazioni di memoria sono il collo di bottiglia e si desidera che questo sia più veloce, la prima soluzione ovvia è utilizzare un buffer contiguo per gli array. Puoi comunque fornire un'interfaccia matrix che li acceda come array bidimensionali.

// Rudimentary Implementation 
template <class T> 
class SquareMatrix 
{ 
public: 
    explicit SquareMatrix(int i_size): 
     size(i_size), mat(new T[i_size * i_size]) {} 

    ~SquareMatrix() 
    { 
     delete[] mat; 
    } 

    // could also be column depending on row-major/col-major 
    T* operator[](unsigned int row) 
    { 
     return mat + row * size; 
    } 

    // could also be column depending on row-major/col-major 
    const T* operator[](unsigned int row) const 
    { 
     return mat + row * size; 
    } 

private: 
    unsigned int size; 
    T* mat; 
}; 

La seconda cosa ovvia da fare è, invece di tre matrici, hanno una matrice composta da una struttura che presenti tutti i dati necessari. Ciò presuppone che una matrice di tuple sia sufficiente, il che sembra essere il caso del codice che hai postato.

Se si vuole davvero eseguire l'hardcore e richiedono più matrici, quindi scrivere il proprio allocatore di memoria per questo. È possibile allocare memoria per più matrici contemporaneamente e semplicemente costruirle utilizzando il posizionamento nuovo. Sono necessarie ulteriori letture e approfondimenti se si desidera eseguire questa operazione poiché la scrittura degli allocatori di memoria non è un compito banale: è necessario considerare problemi come l'allineamento, ma questa è la via più veloce da percorrere.

Ti consiglio di utilizzare un profiler piuttosto che fare affidamento sui test di temporizzazione e di eseguire un'analisi del codice di chiamata corretta. Questo ti dirà esattamente quanto tempo viene speso dove. Potrebbe essere che la costruzione/distruzione degli oggetti nelle matrici non sia così economica come potrebbe essere, per esempio.

A corto di evidenti inefficienze algoritmiche, anche i programmatori estremamente competenti sono spesso errati riguardo ai colli di bottiglia nel loro codice. Il profiler è il tuo migliore amico se l'efficienza è una preoccupazione importante.

0

Se tutti gli oggetti a cui fanno riferimento i puntatori nella matrice sono dello stesso tipo (o almeno della stessa dimensione), è possibile allocare un grosso blocco di memoria per mantenerli tutti e inizializzarli sul posto.

Problemi correlati