Dovresti minimizzare la creazione di molti piccoli oggetti?


10

Quando scrivi qualcosa che crea spesso molti (1000) piccoli oggetti, dovresti cercare di minimizzarlo per le prestazioni? Soprattutto se non sai su quale sistema verrà eseguito, dai desktop di fascia bassa a quella di fascia alta o addirittura mobile. Per i dispositivi mobili, ho sentito che la creazione di molti oggetti ostacola un po 'le prestazioni, anche se non so quanto sia vero.

Ho un esempio che mostra bene questa idea. In un programma di grafica, supponiamo che esista un metodo utilizzato per tutti i disegni idealmente chiamati drawPixel(Point). Potrebbero esserci migliaia di punti creati e può essere ripetuto spesso, come in un gioco in cui potrebbe essere chiamato più di 60 volte al secondo. In alternativa, drawPixel(int x, int y)potrebbe essere utilizzato per ridurre al minimo la creazione di molti oggetti Point.

In un design orientato agli oggetti, penso che sarebbe preferito usare Point. Tuttavia, l'utilizzo di tipi primitivi può aumentare le prestazioni. Il miglioramento delle prestazioni può essere trascurabile nella maggior parte dei casi, ma non sono sicuro di cose come le macchine mobili o vecchie. Qual è il guadagno prestazionale dal fare qualcosa del genere ed è qualcosa che dovrebbe essere preso in considerazione?


Sto facendo fatica a trovare riferimenti per eseguire il backup, ma in generale in Java 8 non ti preoccupare. Non fare cose ovviamente stupide, ma se non sei deliberatamente dispendioso il sistema dovrebbe funzionare bene. Sun / Oracle hanno avuto circa 20 anni per ottimizzare il GC e la gestione della memoria e sono diventati davvero bravi.

@Snowman Ho sentito che le versioni più recenti di Java funzionano meglio con la gestione della memoria, ma il problema che vedo è che non esiste alcuna garanzia che l'utente non stia utilizzando una versione precedente. Fa parte di ciò che ha creato questa mia preoccupazione.
Stripies,

1
Prima di tutto, esegui alcune misurazioni delle prestazioni. Se hai qualche problema, pensa a come ottimizzare. Ma per favore non sacrificare la manutenibilità del codice troppo presto perché pensi che potresti avere dei problemi di prestazioni.
Scoperto il

2
@Stripies Prestazioni di oggetti Java di breve durata già risposto in Dovremmo evitare la creazione di oggetti in Java? . Tuttavia, se mai dovessi gestire centinaia di milioni di tali oggetti al secondo, solo a quel punto riconsidera questo problema.
rwong,

1
Se sei preoccupato per le versioni precedenti di Java, verificalo al momento dell'installazione. Una JVM abbastanza vecchia da causare un problema con la gestione della memoria, ha anche molti problemi di sicurezza ben noti, quindi spingere gli utenti ad aggiornare fa loro un favore. System.getProperty("java.version")(o "java.vm.version") è un punto di partenza.
Jerry Coffin,

Risposte:


17

In generale, no , non dovresti evitare di creare oggetti per paura di perdere prestazioni. Ci sono diverse ragioni per questo.

  1. L'uso degli oggetti è una specie del punto di utilizzo di Java. Evitarli preventivamente è un segno che la decisione di utilizzare Java potrebbe non essere stata quella giusta per cominciare.
  2. I problemi di prestazioni sono notoriamente difficili da prevedere. Non dare mai per scontato che qualcosa sia un collo di bottiglia. Misura sempre . L'ingegneria delle prestazioni è quasi sempre una questione di apportare piccole modifiche esattamente nel posto giusto. Non è possibile prevedere il posto giusto senza misurare più di quanto si possa prevedere l'effetto di un farmaco senza un esperimento.
  3. Il costo della creazione di oggetti è notevolmente sopravvalutato. In una JVM moderna equivale sostanzialmente all'incremento di un puntatore (e con i garbage collector generazionali, anche il costo di gestione è banale). Ci sono molti testi su Internet che ti consigliano di evitare oggetti, di usare il pool di oggetti ecc. Questo consiglio a volte era proprio negli anni '90; oggi è per lo più obsoleto. È molto improbabile che tu ottenga prestazioni sufficienti per giustificare il costo di sviluppo aggiunto e la complessità introdotti evitando oggetti o gestendoli da soli.

Detto questo, ci sono posti in cui trasformare qualcosa in un oggetto non ha senso iniziare. Passare due coordinate a una routine di disegno potrebbe essere un caso del genere: la coppia di coordinate non ha esistenza indipendente, non ha identità, viene utilizzata solo una volta e quindi immediatamente scartata, ecc.

Se questo è il caso, allora vai avanti e passa due intsecondi invece di avvolgerli in un oggetto. Il punto di OOP non è che tutto deve essere un oggetto. Il punto è che gli oggetti semplificano lo sviluppo in luoghi in cui rappresentano la soluzione naturale a un problema di rappresentazione dei dati. Non evitare gli oggetti dove hanno senso - non introdurli dove non hanno.


2

Quando contempli gli impatti sulle prestazioni prima di aver scritto il codice, dovresti presumere che non sai cosa stai facendo.

C'è un piccolo spazio in testa per gli oggetti in Java rispetto ai primitivi. Più piccoli sono i tuoi oggetti, maggiore sarà la percentuale di sovraccarico. Tuttavia, ho imparato molto tempo fa che le cose che raddoppiano n non sono nulla rispetto alle cose che si moltiplicano n per n.

Quindi, anche se sì, potresti creare un sistema che ha avuto un impatto della metà delle dimensioni o addirittura un quarto, ma chiediti perché ti interessa davvero. Le soluzioni complicate a questo problema non saranno ben accolte. Soprattutto perché l'immersione in tale codice sarà confusa. I programmatori confusi scrivono codice errato. Scrivono n volte n codice che dovrebbe essere n registro n codice. E impiegano più tempo per farlo.

Ora se riesci a salvarmi spazio con qualche trucco che si adatta in una bella scatola che non devo guardare dentro la maggior parte del tempo che possiamo parlare. Se è una scatola che posso scambiare con un'altra scatola quando quella scatola funzionerebbe meglio, potrei anche pagarla.


2

Nell'ottimizzazione delle prestazioni che ho fatto ( esempio ) è molto facile che la gestione della memoria sia un grave colpevole. Non mi importa quanto follemente abbiano messo a punto il nuovo operatore e il garbage collector, il calcolo più veloce non è un calcolo. Quindi, se trovo che il gestore della memoria impiega una buona percentuale di tempo e non posso evitare di creare oggetti , allora trovo un modo per riutilizzarli, piuttosto che crearne costantemente di nuovi.

Ho solo fare questo se io devo rendere gli oggetti. Per la grafica, di solito no. IMHO, la grafica dovrebbe essere disegnata , non costruita . Certo, potresti dire che un'immagine è composta da punti, linee che le collegano, poligoni, testo e così via. Ciò non significa che non hai alternativa alla creazione di oggetti da essi prima di disegnarli . Li disegno e basta.

C'è un metodo Paint. Lo sovrascrivo, disegno tutto su una bitmap e quindi blocco trasferendolo sullo schermo. Sembra istantaneo. Per l'input del mouse, ci sono metodi per sovrascrivere, rilevare clic, trascinamento o altro.

OOP è una buona idea per alcune ragioni. Questi motivi non si applicano in tutte le situazioni.


Sono d'accordo, ma sono anche d'accordo con tutti gli altri sul fatto che i test sono l'unico modo per saperlo con certezza. Assicurati di avere le specifiche che lo fanno in modo semplice / ovvio prima di ottimizzarlo ... ma sono d'accordo che il nuovo può ancora essere un problema.
Bill K,

2

Vai avanti e usa piccole allocazioni. I moderni gestori di memoria, in particolare il gestore di oggetti Java altamente ottimizzato, sono estremamente efficienti. Salva l'ottimizzazione delle prestazioni principali per un programma di lavoro.

È estremamente probabile che le prestazioni complessive siano adeguate. Se trovi che non è così, allora, e solo allora , profila le prestazioni del codice. In una lunga carriera nello sviluppo di software, ho imparato che i colli di bottiglia non sono quasi mai previsti.

Una volta un membro del team ha trascorso diversi giorni a rendere la ricerca dei membri dell'oggetto 20 volte più veloce. Successo! Tuttavia, il miglior speedup complessivo nell'uso effettivo è stato misurato in centesimi di percento. La modifica è stata immediatamente ripristinata, poiché l'accelerazione ha richiesto allocazioni di memoria maggiori per membro.


1

È semplice: se hai bisogno di 1000 piccoli oggetti, allora crei 1000 piccoli oggetti e non ti preoccupare. Se hai bisogno di 100 piccoli oggetti, creare 1000 piccoli oggetti è stupido: crea quelli di cui hai bisogno e non di più.

Se sei preoccupato per le prestazioni (e se non sei preoccupato anche per le prestazioni) dovresti avere qualsiasi funzionalità scritta una volta in un unico posto, il che rende l'intero codice più semplice e più facile da capire. Quindi, se si riscontra un problema di prestazioni, la misurazione potrebbe indicare che esiste un punto in cui si verifica il problema di prestazioni, il che semplifica le cose e un solo punto in cui è necessario modificarlo. O la misurazione mostra che questo posto non causa alcun problema, quindi il gioco è fatto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.