La dimensione ottimale del buffer dipende da una serie di fattori: dimensione del blocco del file system, dimensione della cache della CPU e latenza della cache.
La maggior parte dei file system è configurata per utilizzare blocchi di dimensioni 4096 o 8192. In teoria, se si configura la dimensione del buffer in modo da leggere qualche byte in più rispetto al blocco del disco, le operazioni con il file system possono essere estremamente inefficienti (ad esempio se si configurato il buffer per leggere 4100 byte alla volta, ogni lettura richiederebbe 2 letture di blocchi dal file system). Se i blocchi sono già nella cache, finisci per pagare il prezzo della RAM -> latenza cache L3 / L2. Se sei sfortunato e i blocchi non sono ancora nella cache, paghi anche il prezzo della latenza del disco-> RAM.
Questo è il motivo per cui vedi la maggior parte dei buffer dimensionati come una potenza di 2 e generalmente più grandi (o uguali) della dimensione del blocco del disco. Ciò significa che una delle tue letture dello stream potrebbe comportare letture multiple del blocco del disco - ma quelle letture utilizzeranno sempre un blocco completo - nessuna lettura sprecata.
Ora, questo è un po 'compensato in uno scenario di streaming tipico perché il blocco letto dal disco sarà ancora in memoria quando si preme la lettura successiva (stiamo facendo letture sequenziali qui, dopo tutto) - quindi si finisce pagando la RAM -> L3 / L2 prezzo di latenza della cache alla lettura successiva, ma non la latenza del disco-> RAM. In termini di ordine di grandezza, la latenza del disco-> RAM è così lenta che praticamente inonda qualsiasi altra latenza con cui potresti avere a che fare.
Quindi, sospetto che se hai eseguito un test con dimensioni della cache diverse (non l'ho fatto da solo), probabilmente troverai un grande impatto della dimensione della cache fino alla dimensione del blocco del file system. Inoltre, sospetto che le cose si livellerebbero abbastanza rapidamente.
Ci sono un sacco di condizioni ed eccezioni qui - le complessità del sistema sono in realtà piuttosto sconcertanti (solo ottenere un controllo su L3 -> I trasferimenti di cache L2 è incredibilmente complesso e cambia con ogni tipo di CPU).
Questo porta alla risposta del "mondo reale": se la tua app è simile al 99% là fuori, imposta la dimensione della cache su 8192 e vai avanti (ancora meglio, scegli l'incapsulamento rispetto alle prestazioni e usa BufferedInputStream per nascondere i dettagli). Se fai parte dell'1% delle app che dipendono fortemente dalla velocità effettiva del disco, crea la tua implementazione in modo da poter scambiare diverse strategie di interazione del disco e fornire le manopole e i quadranti per consentire agli utenti di testare e ottimizzare (o trovare alcuni sistema di ottimizzazione automatica).