Dipende da come viene "caricato" l'oggetto Image contenuto nel ImageIcon.
Spiego meglio: la classe ImageIcon si può creare in svariati modi (vedi costruttori). Se usi ad esempio i costruttori
ImageIcon(String filename)
ImageIcon(URL location)
(e le altre varianti che aggiungono il String description)
il caricamento materiale della immagine da file/url è delegato al java.awt.Toolkit di AWT, più precisamente al suo metodo getImage( ... )
Il getImage (s)fortunatamente gestisce un meccanismo di "caching" delle immagini. Per più chiamate del getImage() con lo stesso medesimo filename/url, fornisce lo stesso oggetto Image. Quindi effettivamente tiene "in vita" gli oggetti Image anche se poi tu NON li usi più.
La documentazione del Toolkit lo dice chiaramente: The underlying toolkit attempts to resolve multiple requests with the same filename to the same returned Image.
Il modo per liberare le risorse della immagine c'è, è il flush() del Image. Attenzione, che questo NON impedisce il caching del Toolkit o toglie la immagine dalla cache del Toolkit.
Se NON vuoi questo meccanismo di caching, devi caricare tu la immagine in altro modo: tramite il createImage() del Toolkit (che è simile al getImage ma SENZA il caching) oppure come BufferedImage con la API ImageIO.
Nota che il ImageIcon(byte[] imageData) delega al createImage, non al getImage. Ma questa forma generalmente è poco/raramente utile.
Se non viene usato quel (o qualunque altro) meccanismo di caching se hai un oggetto Image ed esso diventa non più raggiungibile, verrà certamente garbage-collected.