[java] BufferedImage erg groot

Pagina: 1
Acties:

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 23-05 22:13

Tjeerd

Be Original, Be Yourself.

Topicstarter
In mijn Java toepassing maak ik gebruik van een BufferedImage, waarin ik iets teken en vervolgens deze buffer 'swap' naar mijn echte tekenpaneel toe. Werkt prima allemaal, alleen gegenereerde plaatje is behoorlijk groot, 4500x4500 pixels (x 3bytes= gauw 60 MB ongeveer aan geheugen wat nodig is.

Ik geef nu een parameter op in de prompt om aan te geven dat er 70 MB geheugen moet worden gereserveerd, dit werkt prima. Wat er gebeurt tijdens het laden:

[functie bestand inladen]
- width en height worden bepaald adhv gegevensbestand.
- BufferedImage buffer = new Image(width, height, type);

1e keer inladen gaat prima, maar als ik meer dan 1 keer hetzelfde bestand wil inladen dan krijg ik een OutOfMemoryError. Enige wat helpt om meer dan 1x bestand te kunnen inladen is om als parameter aan java mee te geven dat er 170 (!) MB geheugen moet worden gereserveerd, anders krijg ik een OutOfMemoryError. Beetje teveel van het goede lijkt me, ik heb dus het idee dat hij 2x de imagebuffer gaat reserveren oid, ik dacht het te kunnen oplossen door de 'buffer' op null te zetten, maar dat is geen oplossing. Ook de GC aanroepen met System.gc() is niet een oplossing of een dumme buffer creeeren door: buffer = new Imagebuffer(1,1,type) te doen -- zodat ie kleiner zou worden eerst -- werkt niet.

--

Vreemde is dat ik het in JProfiler heb getest en daar wordt in totaal niet meer dan 170 MB geheugen gebruikt (ook na meerdere keren inladen). Ik moet dan dus ook aan java als parameter opgeven dat ie 170 MB geheugen moet reserveren. Ik wordt er niet blij van, want kans is groot dat er plaatjes moeten worden gegenereerd van zelfs 10K bij 10K pixels.

Is er misschien sowieso een betere aan te raden methode, of kan iemand me helpen met dit probleem?

[ Voor 12% gewijzigd door Tjeerd op 25-06-2004 11:44 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


Verwijderd

Het lijkt me dat je monitor niet op 4500x4500 pixels draait. Dus waarom zo'n groot plaatje allocaten als je maar een deel ervan kan zien.

1024 x 786 x 3 = 2.25 MB

Je moet dan alleen iets meer teken werk verrichten als je gaat scrollen, maar je bent dan van je mem probleem af en gebruikt niet onnodig veel mem.

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 23-05 22:13

Tjeerd

Be Original, Be Yourself.

Topicstarter
Nee ok, m'n monitor draait ook niet op die resolutie, maar ik maak gebruik van een Scrollpane om zodoende het plaatje te kunnen scrollen binnen het venster. En het is een visualisatie van gegevens en moet echt zo groot zijn kwa pixel-afmetingen :)

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


Verwijderd

Ik zie het probleem niet helemaal. Als je inderdaad zulke grote images moet maken dan heb je ook veel geheugen nodig. 4500x4500x3bytes = 60 MB... so be it!
Je hebt zat geheugen in je computer, wees niet bang om het te gebruiken. Zet Java op 256MB, als het werkt dan werkt het.

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 23-05 22:13

Tjeerd

Be Original, Be Yourself.

Topicstarter
Ok, dat het veel geheugen gebruikt heb ik me al bij neer gelegd, maar het lijkt wel of er twee keer geheugen wordt gereserveerd en daarna niet meer :?

Terwijl bij het inladen van een bestand alleen maar dit wordt gedaan (telkens):

Java:
1
2
// (...code om te bepalen wat grootte en breedte moet worden van buffer...)
buffer = new BufferedImage(width, height, type);


Ik zou eigenlijk bij het inladen van het bestand de buffer eerst willen kunnen legen oid en dan weer opnieuw initialiseren met de juiste grootte. En niet dat ie na meer dan 1x inladen van 70 naar ineens 170 MB schiet. Hij reserveert volgens mij een hele nieuwe buffer (erbij) en dat wil ik nou juist niet.

[ Voor 33% gewijzigd door Tjeerd op 25-06-2004 12:06 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 23-05 16:37

voodooless

Sound is no voodoo!

Over het geheugen moet je je niet druk maken, java lust nog wel eens graag wat. Verder weet je natuurlijk nooit zeker of er idd 3 bytes worden gebruikt voor een pixel. Vaak wordt namelijk ook gewoon een 32-bit's int gebruikt, of 4 bytes (effectief hetzelfde).

Probeer eens java met "-Xincgc" aan te roepen. Dat wil in gevallen van veel geheugenegebruik nogal veel schelen. Ik heb het zelf eens zo erg gehad dat een thread moest maken die in intervallen de gc moest aanroepen om het een beetje in de hand te houden ;) Werd alles vreselijk traag van. Irri als je van die slurpende libs gebruike :(

BTW: hoezo wil je meer dan een keer hetzelfde bestand inlezen?

[ Voor 7% gewijzigd door voodooless op 25-06-2004 12:53 ]

Do diamonds shine on the dark side of the moon :?


  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 23-05 22:13

Tjeerd

Be Original, Be Yourself.

Topicstarter
Naja, het meer dan 1 keer inlezen bedoel ik mee:
- start progsol
* 1. kies bestand in en visualiseer
* 2. kies ander bestand en visualiseer die ook
* 3. herhaal stap 2 oneindig veel keren indien gewenst

Gaat er dus om dat mensen gewoon een ander bstand kunnen kiezen, maar de grootte varieert nogal. Dus ik kan niet standaard zeggen "ik maak een imagebuffer aan van 5000x5000 pixels", soms wordt de visualisatie van bestand > 5000x5000 pixels en soms is het kleiner.

Maar het probleem zit hem ergens in die BufferedImage buffer die wordt aangemaakt volgens mij, want in de functie om het bestand in te lezen staat ongeveer het volgende:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class mijnpseudoclass
{
private BufferedImage buffer = null;
private Graphics2D g2buffer;

public void setup(int theX, int theY, File bestand)
{
//width en height worden afhankelijk van bestandsgrootte gezet 

buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g2buffer = buffer.createGraphics();

dovisualisatie(); // is gewoon tekenen
}
}


En alleen dit stukje code gebruik ik om de buffer aan te maken. De 1e keer is het dus 4500x4500 pixels (~ 60 MB geheugengebruik zie ik in JProbe) en de tweede keer laden van een bestand -- weer deze functie die wordt aangeroepen dus -- wordt er ineens nog eens zo'n brok geheugen van ~60 MB gereserveerd :?

[ Voor 58% gewijzigd door Tjeerd op 25-06-2004 13:34 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 23-05 16:37

voodooless

Sound is no voodoo!

Probeer eens voor die new BufferedImage:

buffer = null; // eventueel de gc aanroepen

Ik heb laatst ergens gelezen dat dat nog wel eens wil helpen in dit soort gevallen.

[ Voor 34% gewijzigd door voodooless op 25-06-2004 14:00 ]

Do diamonds shine on the dark side of the moon :?


  • DaCoTa
  • Registratie: April 2002
  • Laatst online: 21-05 22:50
Als je jprofiler hebt, moet je met de hotspot en GC analyse kunnen achterhalen of en waar die eerste image buffer wordt vastgehouden.

Verder: is je visualisatie erg complex om op te bouwen? Indien nee: dan kan je idd beter met een virtuele view werken zodat je alleen wat op je scherm staat moet tekenen.

Ander idee, mocht het opbouwen te langzaam zijn: breek je image op in tiles van beperkt formaat, zeg 100x100. Teken al deze tiles en cache ze op disk. Als je dan met een virtuele view werkt, lees je de tiles in die je nodig hebt, stopt ze een een LinkedHashMap (lees javadoc voor een mooie en eenvoudige cachebuffer implementatie) en tekent ze op het scherm.

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 23-05 22:13

Tjeerd

Be Original, Be Yourself.

Topicstarter
DaCoTa: idd zat ik daar ook al over te denken, maar het is nogal veel werk om dat voor elkaar te krijgen, maar een optie is het wel :)

Maar ik heb het opgelost, hoe simpel kan het zijn:

Java:
1
2
3
4
5
//pseudo-code
buffer = new BufferedImage(width, height, type);
 g2buffer = buffer.createGraphics(buffer);
 System.gc(); // *hier* dus pas de garbage collector aanroepen (aan het eind)
//niet nadat de variabele 'buffer' is aangemaakt, want dat werkte niet

Het is eigenlijk zo simpel :+, geheugengebruik blijft nu rond de 100 MB hangen, alleen de maxheap grootte stijgt nog wel steeds tot ongeveer ruim 200 MB, dat blijft wel vaag en ben ook verplicht om de optie -Xmx256 te doen, die optie niet meegeven zorgt er voor dat het helemaal niet werkt (OutOfMemoryError).

[ Voor 28% gewijzigd door Tjeerd op 25-06-2004 15:02 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.

Pagina: 1