Portál AbcLinuxu, 9. května 2025 23:34

Dotaz: Java

10.8.2009 15:28 L.A.
Java
Přečteno: 371×
Odpovědět | Admin

Dobry den, delam program na prohlizeni obrazku. Na zacatku mi nasledujici metoda nacte vsechny obrazky. V seznamu imageNames jsou jmena vsech obrazku v urcite slozce.

private void loadImages()
    {
        mediaTracker = new MediaTracker(this);
        Toolkit toolkit = Toolkit.getDefaultToolkit();

        for (String imageName : imageNames)
            images.add(toolkit.getImage(imageName));

        for (int i = 0; i < 10; i++)
            mediaTracker.addImage(images.get(i), i);

        try
        {
            for (int i = 0; i<10; i++)
                mediaTracker.waitForID(i);
        } catch (InterruptedException ex)
        {
            ex.printStackTrace();
        }
    }

Pres mediaTracker.addImage() a mediaTracker.waitForID() nactu a pridam pouze prvnich 10 obrazku - kdybych nacetl vsechny tak zbytecne zaplacam RAM a trvalo by to hoodne dlouho.

Potom mam metodu pro zobrazeni nasledujiciho obrazku po stisku sipky doprava:

private void drawNextImage()
    {
        if ((++imageIndex) == images.size())
            imageIndex = 0;
        // ic je Canvas do ktereho obrazek vykresluji
        ic.drawLoadedImage(images.get(imageIndex));
        ...
        mediaTracker.addImage(images.get(imageIndex+10), imageIndex+10);
        try
        {
            mediaTracker.waitForID(imageIndex+10);
        } catch (InterruptedException ex)
        {
            ex.printStackTrace();
        }

        if ((imageIndex - 10) >=  0)
            mediaTracker.removeImage(images.get(imageIndex - 10), imageIndex - 10);
    }

V promenne imageIndex je index aktualniho zobrazeneho obrazku. V te metode si tedy pripravim nasledujici jeste nenacteny obrazek, tzn ten na indexu imageIndex+10 a zaroven ten o 10 mist dozadu (pokud je to mozne) odstranim. Mam tedy v pameti nacteno vzdy jen male mnozstvi obrazku, ne vsechny.

Program testuji v adresari, kde mam 65 fotek, zadna asi 2MB. Prvnich 10 fotek je uz prednactenych, takze se vzdy po stisku sipky doprava zobrazi velmi rychle, u 11. fotky je uz poznat rozdil a vzdy kolem 30. fotky dostanu toto:

Exception in thread "Image Fetcher 1" java.lang.OutOfMemoryError: Java heap space
        at java.awt.image.DataBufferInt. init (DataBufferInt.java:41)
        at java.awt.image.Raster.createPackedRaster(Raster.java:458)
        at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1015)
        at sun.awt.image.ImageRepresentation.createBufferedImage(ImageRepresentation.java:230)
        at sun.awt.image.ImageRepresentation.setPixels(ImageRepresentation.java:484)
        at sun.awt.image.ImageDecoder.setPixels(ImageDecoder.java:120)
        at sun.awt.image.JPEGImageDecoder.sendPixels(JPEGImageDecoder.java:97)
        at sun.awt.image.JPEGImageDecoder.readImage(Native Method)
        at sun.awt.image.JPEGImageDecoder.produceImage(JPEGImageDecoder.java:119)
        at sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:246)
        at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:172)
        at sun.awt.image.ImageFetcher.run(ImageFetcher.java:136)

Pak mohu jeste dolistovat k cca 40. fotce - to dava smysl, protoze 10 fotek dopredu je prednactenych a pote se fotky uz vubec nezobrazuji. Pro jednoduchost jeste neresim to ze nacitam fotky z indexu, ktery uz neexistuje (je vetsi nebo roven images.size())

Proto otazka - jak mam tu pamet uvolnovat, abych predesel OutOfMemoryError?

Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

10.8.2009 16:50 cronin | skóre: 49
Rozbalit Rozbalit vše Re: Java
Odpovědět | | Sbalit | Link | Blokovat | Admin
Treba zariadit, aby sa nikde nerzali referencie na tie objekty; v Tvojom pripade patrne v objekte MediaTracker. Treba si uvedomit, ze obrazok v programe obsahuje dekomprimovane bitmapove udaje vo formate ARGB a je teda omnoho vacsi ako JPEG/PNG subor na disku.

Pozri tiez toto:

http://code.google.com/p/javagems/source/browse/trunk/srcs/gems/easteregg/shower/Shower.java
10.8.2009 17:48 L.A.
Rozbalit Rozbalit vše Re: Java

No prave kvuli tomu, aby se dany objekt obrazku z MediaTrackeru odstranil volam toto:

mediaTracker.removeImage(image, index);

K cemu pak ta metoda slouzi? V tom kodu Shower.java jsem nenasel nic co by mi s timto pomohlo, mel jste tam na mysli neco konktretniho?

10.8.2009 18:01 cronin | skóre: 49
Rozbalit Rozbalit vše Re: Java
Skus znizit hranicu 10 obrazkov, ale nastavit vacsi heap pomocou -Xmx; inac povedane, je mozne ze ani tych 10 obrazkov sa do defaultneho heapu nezmesti.
10.8.2009 18:54 L.A.
Rozbalit Rozbalit vše Re: Java

Ok, zkusil jsem tu hranici 10 snizit na 1, takze nacitam pouze jeden obrazek dopredu. Takto to zvladlo 37 fotek (predtim 30) a na 38 zase ta chyba.

Nechal jsem hranici stale na 1 jeda a program spustil s -Xmx1024m coz by melo programu poskytnout giga pameti, jestli jsem to dobre pochopil - takto to zvladlo 56 fotek, 57 hodila moji oblibenou chybu. Jak je prosim mozny, ze takovy programek na prohlizeni obrazku s predbufferovanim jednoho obrazku sezere 1GB RAM? Jedine prijatelne vysvetleni je asi to, ze ty nactanene obrazky stale zustavaji v pameti, co myslite?

Doted jsem automatickou spravu pameti v Jave bral jakou velkou vyhodu oproti treba C++, ale nyni mi pekne komplikuje zivot... Nejake navrhy?

10.8.2009 19:13 cronin | skóre: 49
Rozbalit Rozbalit vše Re: Java
Odpovědět | | Sbalit | Link | Blokovat | Admin
Ale do premennej images nacitavas vsetky obrazky...
10.8.2009 19:58 L.A.
Rozbalit Rozbalit vše Re: Java

Tak jsem seznam objektu Image odstranil, obrazky nacitam az v pripade potreby podle seznamu imageNames a vypada to, ze to pomohlo. Ja ten problem porad daval za vinu MediaTrackeru a on az to mohl obycejny seznam objektu Image... zajimave.

10.8.2009 20:07 cronin | skóre: 49
Rozbalit Rozbalit vše Re: Java
Nic zaujimave na tom nieje; ten zoznam jednoducho drzal zive referencie na vsetky objekty Image; akekolvek ich odstranovanie z trackera ich uvolneniu z pamate nemohlo pomoct. Mozem sa Ti zarucit, ze garbage collection v Jave funguje sakramensky dobre.

Este odporucam pozriet si javadoc k Tookit.getImage() a Image.flush().
10.8.2009 21:01 moira | skóre: 30 | blog: nesmysly
Rozbalit Rozbalit vše Re: Java
No spise nez zajimave je to naprosto normalni :) To, ze jsi odstranil obrazek z MediaTrackeru je sice fajn, ale v kolekci images na ten obrazek porad zustaval odkaz, takze ho GC nemohl odstranit. Jinak to, co se ti prave prihodilo, je typicky priklad "memory leakage" v Jave.
Překladač ti nikdy neřekne: "budeme kamarádi"

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.