|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
[Java] Anteprima immagini... problema memoria
Salve a tutti, stavo sviluppando un programma che mi permettesse di avere in un JPanel sulla sinistra le anteprime delle immagini contenute nella cartella di cui ho aperto il file immagine.
I problemi qui ora sono 2: -Se le immagini sono di dimensioni abbastanza grandi 4000x3000 px circa (all'incirca la grandezza in cui salva le foto la mia macchina fotografica) dopo che ne carica qualche d'una java mi da un errore di memoria (heap space se non sbaglio)... ho semi risolto aumentando la memoria che la jvm può usare ma non mi sembra una risoluzione molto carina... -In secondo luogo ho notato che quando viene richiamato il metodo per creare nuovamente le anteprima (è stata quindi cambiata cartella) gli elementi precedenti non vengono cancellati dalla memoria neanche con il comando System.gc() e quindi ben presto la memoria sale e mi da nuovamente l'errore precedentemente citato... C'è qualche soluzione? |
|
|
|
|
|
#2 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
Ho fatto un piccolo programma d'esempio cosi potete provarlo e darmi qualche consiglio.
Vi dico subito che ho notato che anche se rimuovo i componenti e chiamo il metodo System.gc() le immagini restano in memoria infatti se carico un'altra cartella e poi decido di caricare di nuovo la prima la memoria non sale. Il problema è che non so come rimuoverli. Premetto che nell'esempio l'ho fatto cosi al volo ma nel mio programma utilizzo i thread per non bloccare tutto il programma con il caricamento immagini, ma la situazione è identica tanto in questo caso mostro solo le anteprime... Nel mio caso lo devo avviare con l'opzion -Xmx512m per avere un po' più di ram in modo che non mi si blocchi dopo 4 o 5 immagini per vie del problema per le grandi dimensioni che ho spiegato in precedenza Codice:
public class Main extends JFrame {
JPanel p = new JPanel();
JMenuBar mb = new JMenuBar();
JMenu m = new JMenu("File");
JMenuItem mi = new JMenuItem("Apri");
JMenuItem mm = new JMenuItem("Rimuovi");
public Main() {
aggiungiComponenti();
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if(fc.showOpenDialog(p) == JFileChooser.APPROVE_OPTION)
azione(fc.getSelectedFile());
}
});
mm.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
p.removeAll();
p.updateUI();
}
});
}
public void aggiungiComponenti() {
add(p);
mb.add(m);
m.add(mi);
m.add(mm);
setJMenuBar(mb);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
}
public void azione(File dir) {
if(p.getComponentCount() != 0) {
p.removeAll();
p.updateUI();
}
File f[] = dir.listFiles();
ImageIcon icons[] = new ImageIcon[f.length];
for (int i = 0; i < f.length; i++) {
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);
icons[i] = new ImageIcon(f[i].getAbsolutePath(), f[i].getName());
ImageIcon adactIcon = new ImageIcon(getScaledImage(icons[i].getImage(), 100, 100));
JButton thumbButton = new JButton(adactIcon);
thumbButton.setAlignmentX(JButton.CENTER_ALIGNMENT);
p.add(thumbButton);
p.revalidate();
}
}
private Image getScaledImage(Image srcImg, int w, int h){
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main();
}
});
}
}
|
|
|
|
|
|
#3 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
UP
|
|
|
|
|
|
#4 |
|
Member
Iscritto dal: May 2007
Città: Roma
Messaggi: 93
|
Ecco fatto...
Ho aggiunto una riga nel main... tanto per promuovere il nuovo look&feel di java... Serve almeno Java 6u10 per vederlo.... (è uscita la 6u11 da poco) Comunque semplice il problema è che ti salvavi tutte le foto nell'array... Codice:
public class Main extends JFrame {
JPanel p = new JPanel();
JMenuBar mb = new JMenuBar();
JMenu m = new JMenu("File");
JMenuItem mi = new JMenuItem("Apri");
JMenuItem mm = new JMenuItem("Rimuovi");
public Main() {
aggiungiComponenti();
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (fc.showOpenDialog(p) == JFileChooser.APPROVE_OPTION)
azione(fc.getSelectedFile());
}
});
mm.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
p.removeAll();
p.updateUI();
}
});
}
public void aggiungiComponenti() {
add(p);
mb.add(m);
m.add(mi);
m.add(mm);
setJMenuBar(mb);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
}
public void azione(File dir) {
if (p.getComponentCount() != 0) {
p.removeAll();
p.updateUI();
}
File f[] = dir.listFiles();
for (int i = 0; i < f.length; i++) {
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);
ImageIcon adactIcon = new ImageIcon(getScaledImage(new ImageIcon(f[i].getAbsolutePath(), f[i].getName()).getImage(), 100, 100));
JButton thumbButton = new JButton(adactIcon);
thumbButton.setAlignmentX(JButton.CENTER_ALIGNMENT);
p.add(thumbButton);
p.revalidate();
}
}
private Image getScaledImage(Image srcImg, int w, int h) {
BufferedImage resizedImg = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(new NimbusLookAndFeel());
} catch (UnsupportedLookAndFeelException e) {}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main();
}
});
}
}
comunque ti consiglio di usare il foreach molto che più pulito... ad esempio Codice:
public void azione(File dir) {
if (p.getComponentCount() != 0) {
p.removeAll();
p.updateUI();
}
File f[] = dir.listFiles();
for (int i = 0; i < f.length; i++) {
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);
ImageIcon adactIcon = new ImageIcon(getScaledImage(new ImageIcon(f[i].getAbsolutePath(), f[i].getName()).getImage(), 100, 100));
JButton thumbButton = new JButton(adactIcon);
thumbButton.setAlignmentX(JButton.CENTER_ALIGNMENT);
p.add(thumbButton);
p.revalidate();
}
}
Codice:
public void azione(File dir) {
if (p.getComponentCount() != 0) {
p.removeAll();
p.updateUI();
}
for (File f : dir.listFiles()) {
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);
ImageIcon adactIcon = new ImageIcon(getScaledImage(new ImageIcon(f.getAbsolutePath(), f.getName()).getImage(), 100, 100));
JButton thumbButton = new JButton(adactIcon);
thumbButton.setAlignmentX(JButton.CENTER_ALIGNMENT);
p.add(thumbButton);
p.revalidate();
}
}
__________________
Più ti avvicini alla luce, più la tua ombra diventa grande (Kingdom Hearts - Walt Disney e Squaresoft, ma la mano è della Squaresoft) |
|
|
|
|
|
#5 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
quale array? se intendi l'array di file ho provato a modificarlo come dici te ma la situazione non cambia
|
|
|
|
|
|
#6 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
piuttosto vorrei dire che ieri sera mi sono accorto che usando la classe ImageIO si usa meno memoria e arrivo anche a liberarla ad ogni chiamata del metodo.
Però vorrei comunque sapere dove sbaglio in questa situazione perchè ci sarà qualcosa che dovrei fare ma non faccio dato che le immagini restano in memoria non so dove... grazie |
|
|
|
|
|
#7 |
|
Member
Iscritto dal: May 2007
Città: Roma
Messaggi: 93
|
strano a me dava problemi ho modificato così e si è risolto....
evidentemente con una cartella con ancora più immagini il problema persiste... ora provo a farne una con un centinaio di immagini..... PS: ... mi funziona ho caricato ora molte immagini... (l'array che causa problemi non è quello sui File... quella era solo una cosa che ti ho detto per fini estetici...) fai copia incolla della classe che ho postato prima, e provala
__________________
Più ti avvicini alla luce, più la tua ombra diventa grande (Kingdom Hearts - Walt Disney e Squaresoft, ma la mano è della Squaresoft) Ultima modifica di Dark Phoenix : 13-12-2008 alle 13:26. |
|
|
|
|
|
#8 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
Io sto facendo il test su 2 cartelle di circa 10 file ognuna di dimensioni intorno ai 3000x2000px:
carico la prima e arriva circa a 300 mb di ram poi carico rimuovo poi carico la seconda e va a circa 500 poi rimuovo e se ricarico la prima me la carica al volo senza che la memoria salga quindi probabilmente le immagini persistono anche se non so come |
|
|
|
|
|
#9 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
ma quella classe è uguale alla mia... l'ho provata e la memoria comqune non mi si azzera
|
|
|
|
|
|
#10 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
ah ho capito! ok ma perchè toglieno la riga dove dichiari e inizializzi la prima icona cambia cosi tanto il programma?
Ho visto ora che hai sostituito questa: Codice:
ImageIcon icons = new ImageIcon(f[i].getAbsolutePath(), f[i].getName()); ImageIcon adactIcon = new ImageIcon(getScaledImage(icons.getImage(), 100, 100)); Codice:
ImageIcon adactIcon = new ImageIcon(getScaledImage(new ImageIcon(f[i].getAbsolutePath(), f[i].getName()).getImage(), 100, 100)); Ultima modifica di +HookTheGhost+ : 13-12-2008 alle 13:38. |
|
|
|
|
|
#11 |
|
Member
Iscritto dal: May 2007
Città: Roma
Messaggi: 93
|
Per dirla semplice quello che fai è caricare in memoria l'immagine per poi fare il resize e visualizzarla...
Se mantieni l'immagine principale (non "resizata") in un array non consenti al garbage collector di rimuoverla, pertanto la memoria sale proporzionalmente alla dimensione delle immagini inserisci nell'array. Al contrario se ne carichi una alla volta la converti e poi "butti" l'originale il garbage quando necessario provvederà a deallocare l'immagine originale. PS. La cosa importante che ho tolto è questo array qui nel quale salvavi le immagini complete Codice:
ImageIcon icons[] = new ImageIcon[f.length];
__________________
Più ti avvicini alla luce, più la tua ombra diventa grande (Kingdom Hearts - Walt Disney e Squaresoft, ma la mano è della Squaresoft) |
|
|
|
|
|
#12 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
Ah si l'array di icone l'avevo creato per sbaglio in realtà nel mio programma non c'è infatti il problema nn è risolto...
Tento di spiegare cosa ho notato... se non tocco il parametro della jvm -Xmx java usa 64 mb di ram per gestire le foto e fin qui ok, apro il primo set di foto e la ram va a 63, apro il secondo e noto che resta fissa a 63, riapro il primo set di foto e noto che dopo un po' di foto su una particolarmente pesante mi da l'errore Heap Space che indica che sono andato oltre la memoria richiesta... ho provato allora ad avviarlo dandogli non più 64 mb di ram ma 128 è ho notato che caricando il primo set di voto vado salgo già a 127 e ripetendo il procedimento precedentemente descritto ho lo stesso problema Ma com'è possibile che prima riusciva a caricarle usando i 64 mb e ora le stesse foto le carica usando tutti i 128? non può usare solo quelli necessari e accedere agli altri in caso di bisogno? Oppure il Garbage Collector viene chiamato quando si sta per sforare e non prima? |
|
|
|
|
|
#13 |
|
Member
Iscritto dal: May 2007
Città: Roma
Messaggi: 93
|
Probabilmente il problema è da qualche altra parte, se utilizzi il main postato da me il problema c'è?
Il comportamento del Garbage Collector è imprevedibile e fondamentalmente lazy. Più la memoria si sta esaurendo più diventa "aggressivo" il GC. Generalmente il GC viene invocato dalla JVM quando si sta in condizioni critiche, tipicamente quando si è a corto di RAM, comunque il comportamento del GC è del tutto imprevedibile Comunque se vuoi capire bene cosa occupa la tua RAM da java 6u7 se non sbaglio nella jdk è integrato JVisualVM un comodo tool visuale per spulciare i programmi java in esecuzione: puoi controllare thread, fare dump dell'heap e molte altre cose... lo trovi dentro la cartella bin della jdk
__________________
Più ti avvicini alla luce, più la tua ombra diventa grande (Kingdom Hearts - Walt Disney e Squaresoft, ma la mano è della Squaresoft) |
|
|
|
|
|
#14 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
si anche con il tuo prgoramma la cosa sussiste...
Se chiamo io con il comando System.gc() può cambiare qualcosa o non conviene fare operazioni di questo tipo? Ma comunque quello che mi chiedo è a che scopo permettere di usare più memoria se poi viene usata "male"... nel mio caso se riesce a fare il 90 % delle operazioni con 64mb quando gliene do 128 dovrebbe farcela alla grande invece ripete le precedenti prestazioni, mi sembra un po' assurdo... Proverò comunque anche quei tool che mi hai consigliato Spero di riuscire a risolvere prima o poi |
|
|
|
|
|
#15 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
mi correggo il tuo va il problema c'è quando metto il metodo azione in un Thread la cosa dopo un po' salta probabilmente sbaglio io... anzi di fisso
Codice:
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (fc.showOpenDialog(p) == JFileChooser.APPROVE_OPTION) {
final File fl = fc.getSelectedFile();
Thread t = new Thread(new Runnable() {
public void run() {
azione(fl);
}
});
t.start();
}
}
});
|
|
|
|
|
|
#16 | |
|
Member
Iscritto dal: May 2007
Città: Roma
Messaggi: 93
|
Quote:
guarda ho provato a fare così quel metodo... Codice:
public void azione(File dir) {
if (p.getComponentCount() != 0) {
p.removeAll();
p.updateUI();
}
for (File f : dir.listFiles()) {
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);
ImageIcon adactIcon = new ImageIcon(f.getAbsolutePath(), f.getName());
adactIcon = new ImageIcon(adactIcon.getImage().getScaledInstance(100, 100, Image.SCALE_DEFAULT));
JButton thumbButton = new JButton(adactIcon);
thumbButton.setAlignmentX(JButton.CENTER_ALIGNMENT);
p.add(thumbButton);
p.revalidate();
}
}
prova tu su qualcosa di più grande magari ottieni comunque benefici. Scusa se vado a tentativi ma non ho foto grandi e conosco poco java awt e swing
__________________
Più ti avvicini alla luce, più la tua ombra diventa grande (Kingdom Hearts - Walt Disney e Squaresoft, ma la mano è della Squaresoft) |
|
|
|
|
|
|
#17 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
il tuo programma funziona si scusa il problema lo ho quando uso i Thread guarda sopra... mi sa che sbaglio qualcosa nel loro utilizzo (anche se un programma demo di Sun faceva tale e quale)
|
|
|
|
|
|
#18 | |
|
Member
Iscritto dal: May 2007
Città: Roma
Messaggi: 93
|
Quote:
questa volta non riesco a riprodurre quel che ti accade...
__________________
Più ti avvicini alla luce, più la tua ombra diventa grande (Kingdom Hearts - Walt Disney e Squaresoft, ma la mano è della Squaresoft) |
|
|
|
|
|
|
#19 |
|
Member
Iscritto dal: Oct 2008
Messaggi: 56
|
Io ho provato con 2 cartelle una da 20 e l'altra da 130 foto la prima la carica no problem e dopo invece nel caricare la seconda da l'errore... le dimensioni sono sempre le stesse...
|
|
|
|
|
|
#20 |
|
Member
Iscritto dal: May 2007
Città: Roma
Messaggi: 93
|
Perdonami se ti posto tutto il codice, ma è per stare sicuri... non ho foto grandi prova tu con questo...
Codice:
public class Main extends JFrame {
JPanel p = new JPanel();
JMenuBar mb = new JMenuBar();
JMenu m = new JMenu("File");
JMenuItem mi = new JMenuItem("Apri");
JMenuItem mm = new JMenuItem("Rimuovi");
public Main() {
aggiungiComponenti();
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (fc.showOpenDialog(p) == JFileChooser.APPROVE_OPTION) {
final File fl = fc.getSelectedFile();
Thread t = new Thread(new Runnable() {
public void run() {
azione(fl);
}
});
t.setDaemon(true);
t.start();
}
}
});
// mi.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// JFileChooser fc = new JFileChooser();
// fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
// if (fc.showOpenDialog(p) == JFileChooser.APPROVE_OPTION)
// azione(fc.getSelectedFile());
// }
// });
mm.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
p.removeAll();
p.updateUI();
}
});
}
public void aggiungiComponenti() {
add(p);
mb.add(m);
m.add(mi);
m.add(mm);
setJMenuBar(mb);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
}
public void azione(File dir) {
if (p.getComponentCount() != 0) {
p.removeAll();
p.updateUI();
}
for (File f : dir.listFiles()) {
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);
ImageIcon adactIcon = getImage(f);
JButton thumbButton = new JButton(adactIcon);
thumbButton.setAlignmentX(JButton.CENTER_ALIGNMENT);
ImageObserver imageObserver = adactIcon.getImageObserver();
p.add(thumbButton);
p.revalidate();
}
}
private void loadImage(File f) {
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);
ImageIcon adactIcon = getImage(f);
JButton thumbButton = new JButton(adactIcon);
thumbButton.setAlignmentX(JButton.CENTER_ALIGNMENT);
ImageObserver imageObserver = adactIcon.getImageObserver();
p.add(thumbButton);
p.revalidate();
}
private ImageIcon getImage(File f) {
Image i = new ImageIcon(f.getAbsolutePath(), f.getName()).getImage();
Image scaledInstance = i.getScaledInstance(100, 100, Image.SCALE_DEFAULT);
i.flush();
return new ImageIcon(scaledInstance);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(new NimbusLookAndFeel());
} catch (UnsupportedLookAndFeelException e) {}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main();
}
});
}
}
__________________
Più ti avvicini alla luce, più la tua ombra diventa grande (Kingdom Hearts - Walt Disney e Squaresoft, ma la mano è della Squaresoft) |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 08:20.




















