2009-11-23 18 views
6

Nell'applicazione che sto sviluppando, viene utilizzato il controllo DevExpress XtraGrid, che ha un evento RowCellStyle che consente di personalizzare lo stile di ogni cella. I gestori di eventi per questo evento tipicamente assomigliano che:Costo della creazione di oggetti Font in .NET

private gridView1_RowCellStyle(object sender, RowCellStyleEventArgs e) 
{ 
    if (/* Some condition */) 
    { 
     e.Appearance.Font = new Font(gridView1.Appearance.Font, FontStyle.Bold); 
    } 
} 

Questo gestore viene richiamato ogni volta che viene eseguito il rendering di una cella, quindi è in grado di creare un gran numero di casi Font. Quindi mi chiedo quale sia il costo per farlo ... Ho fatto alcuni esperimenti e sembra che ogni volta venga creata una nuova maniglia HFONT. Dovrei preoccuparmi? Quanto è grande l'impatto sull'utilizzo delle risorse?

Se ha un impatto significativo sulle prestazioni, non dovrebbe esserci una classe FontCache o qualcosa di simile?

Nota: io so come risolvere il problema (ho solo bisogno di creare il tipo di carattere, una volta e riutilizzarlo ogni volta), la mia domanda è in realtà circa il costo della creazione di molti HFONT maniglie

+1

Ho accidentalmente avuto un codice simile in un ciclo di rendering del gioco una volta. Penso che sia caduto FPS da> 200 a meno di 40. – Jimmy

+0

L'ottimizzazione prematura è la radice di tutto il male -____-. –

+6

Il licenziamento prematuro delle preoccupazioni relative alle prestazioni è un male meno celebrato. – Jimmy

risposta

6

prova esso; Ottengo circa il doppio delle prestazioni dal riutilizzo (in rilascio, il riutilizzo = 3000ms, ricreare = 4900ms)

using System.Windows.Forms; 
using System.Drawing; 
using System.Diagnostics; 
static class Program 
{ 
    static void Main() 
    { 
     Button btn1, btn2; 
     Form form = new Form 
     { 
      Controls = { 
       (btn1 = new Button { Dock = DockStyle.Bottom, Text = "reuse" }), 
       (btn2 = new Button { Dock = DockStyle.Bottom, Text = "recreate"}) 
      } 
     }; 
     btn1.Click += delegate 
     { 
      var watch = Stopwatch.StartNew(); 
      using (var gfx = form.CreateGraphics()) 
      using (var font = new Font(SystemFonts.DefaultFont, FontStyle.Bold)) 
      {     
       gfx.Clear(SystemColors.Control); 
       for (int i = 0; i < 10000; i++) 
       { 
        gfx.DrawString("abc", font, SystemBrushes.ControlText, i % 103, i % 152); 
       } 
      } 
      watch.Stop(); 
      form.Text = watch.ElapsedMilliseconds + "ms"; 
     }; 
     btn2.Click += delegate 
     { 
      var watch = Stopwatch.StartNew(); 
      using (var gfx = form.CreateGraphics()) 
      { 
       gfx.Clear(SystemColors.Control); 
       for (int i = 0; i < 10000; i++) 
       { 
        using (var font = new Font(SystemFonts.DefaultFont, FontStyle.Bold)) 
        { 
         gfx.DrawString("abc", font, SystemBrushes.ControlText, i % 103, i % 152); 
        } 
       } 
      } 
      watch.Stop(); 
      form.Text = watch.ElapsedMilliseconds + "ms"; 
     }; 
     Application.Run(form); 

    } 
} 
+1

Argomento abbastanza convincente ... grazie! C'è qualche meccanismo di caching dei font esistente in .NET? Non riesco a trovare nulla di simile in System.Drawing ... –

2

Font implementa IDisposable - è necessario assicurarsi di chiamare Dispose quando hai finito con esso.

È una risorsa non gestita, quindi è possibile che il sistema operativo esaurisca le risorse per produrti con più oggetti.

Controllare il conteggio degli handle GDI in TaskManager per vedere se aumenta continuamente.

+0

Inoltre, se stai usando molto quel Font, fallo una volta e riutilizzalo! Non è necessario installarlo continuamente. –

+0

@Sonny Boy - guarda la domanda:> Nota: so come risolvere il problema (ho solo bisogno di creare il font una volta e riutilizzarlo ogni volta), la mia domanda riguarda davvero il costo della creazione di molte maniglie HFONT –

2

Il riutilizzo è quasi sempre più rapido di quello su richiesta, ma la capacità di riutilizzare o memorizzare nella cache gli oggetti Font può variare.

Se si riutilizza oggetti Font e si associano oggetti Font distinti con ogni controllo, si aumenterà la possibilità di scavalcare il limite dell'impegno gdi. Ciò danneggerà tutte le applicazioni in uso da un determinato utente quando si verifica.

Idealmente, è necessario memorizzare nella cache gli oggetti Font a livello di applicazione/processo e solo il set minimo necessario (forse una dozzina circa al massimo). Inoltre, la memorizzazione nella cache di un piccolo insieme condiviso di caratteri e altri oggetti GDI consente di eseguire un lavoro migliore di gestione di messaggi complessi come WM_SETTINGCHANGE. Nel tuo esempio, stai modificando i valori predefiniti e potresti incontrare bug di disegno quando un utente cambia schema o il carattere di visualizzazione predefinito in Windows. Durante WM_SETTINGCHANGE, potresti prendere in considerazione il rilascio delle copie memorizzate nella cache e l'inizializzazione o la preparazione di nuovi set di oggetti font.

WM_SETTINGCHANGE (Windows) @ MSDN

Se avete la necessità di avere centinaia di tipi di carattere vario (o altri oggetti GDI) disponibili, si dovrebbe font non della cache e creare solo quello che ti serve su richiesta. Non è adatto alle prestazioni, ma aiuterà la tua applicazione a coesistere con altre applicazioni che un utente potrebbe avere. Tenere centinaia di oggetti GDI aumenterà notevolmente la probabilità che un utente incontri il limite di handle GDI. Tuttavia, una cache basata sui conteggi di riferimento può fornire un compromesso qui che funziona meglio per te, tenendo in mano le copie solo delle varianti usate più frequentemente.

Infine, come menzionato da Matt Breckon, utilizzare IDisposable per tutti gli oggetti GDI che lo hanno disponibile. Questo ti aiuterà a evitare perdite di gestione.

+0

+1 , buon punto su WM_SETTINGCHANGE se implemento un meccanismo di cache ... –

Problemi correlati