[Java] OutOfMemoryError bij aanmaken Stringbuffer

Pagina: 1
Acties:

  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
Goeiemiddag,

Ik ben nu bezig met een Java Listener app die data binnen krijgt via TCP/IP.

Die data lees ik telkens in een byte array van 1024 bytes. Vervolgens maak ik een string van de gelezen data en die string voeg ik daarna toe aan een stringbuffer.

Mijn lusje ziet er dus als volgt uit:
code:
1
2
3
4
5
6
7
8
9
10
11
String strTemp = "";
StringBuffer sb = new StringBuffer("");
int intBytesRead = 0;
byte jobBytes[] = new byte[1024];

while((intBytesRead = bufferedinputstream.read(jobBytes)) > 0)
{
  // Place de bytes read in a string 
  strTemp = new String(jobBytes, 0, intBytesRead);
  sb.append(strTemp);
}

Mijn probleem is nu dat ik na een KB'tje of 500 de volgende error krijg:
java.lang.OutOfMemoryError

Dat vind ik wel al erg snel. :?
Heeft de Stringbuffer een limiet ingebouwd ofzow :?

De reden dat ik alles in een string inlees is, omdat ik de snelheid optimaal wil houden als ik later met de ingelezen data ga manipuleren.

Hoe kan ik om dit probleem heen gaan werken :?

It’s nice to be important but it’s more important to be nice


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

stringbuffer kan geloof ik wel langer dan 500KB worden, maar of je Heap wel groot genoeg is :?

Knoei eens wat met de *memory* methoden van Runtime ?

  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
De heap size vergroten bleek inderdaad hier wel te helpen.
Toch vind ik dit niet echt een ideale oplossing.

Maar wat ik me afvraag. Als ik de volgende regel uitvoer in het lusje:
code:
1
strTemp = new String(jobBytes, 0, intBytesRead);

Dan wordt toch niet iedere keer geheugen gealloceerd met new, want het weordt steeds in dezelfde string gezet.

It’s nice to be important but it’s more important to be nice


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Dan wordt toch niet iedere keer geheugen gealloceerd met new, want het weordt steeds in dezelfde string gezet.
Jawel, maar ik vind het trouwens wel verbazingwekkend als dat ook de bron van je probleem is omdat elke String garbage is na de loop.

Het is echter wel uitermate inefficient: voor elke keer dat de byte array wordt gevuld (elke loop dus) wordt er een String aangemaakt en dat is iets wat je niet moet doen. Het is nog net iets efficienter dan simpele String optelling, maar het scheelt niet veel ;) .

Ik zou als ik jou was even overstappen op een BufferedReader (wrap de InputStream met een InputStreamReader) en daarna gebruik maken van de char[] functionaliteit ipv bytes. Deze chars kan je gelijk appenden aan de StringBuffer.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Btw: dat je dezelfde variabele gebruikt voor die String zorgt er niet voor dat het elke keer hetzelfde String object is (Strings zijn sowieso immutable). De declaratie buiten de loop heeft in feite geen enkele nut: met new wordt altijd een nieuw object aangemaakt en de oude waarde van de variable is garbage.

Dit topic is relevant:
http://forum.javahova.net/topic.php?id=641

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
Once again thanks voor deze nuttige replies.
Ik zal aan de hand van je tips kijken hoe ik de loop kan optimaliseren.

It’s nice to be important but it’s more important to be nice


  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
Zoals mbravenboer voorstelde ben ik nu met een InputStreamReader en BufferedReader gaan werken ipv een
Bufferedinputstream.
Echter nu werk ik met een character array ipv een byte array en dat levert problemen op.
Dit is mijn nieuwe code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
isr = new InputStreamReader(socket.getInputStream());
br = new BufferedReader(isr);
StringBuffer sb = new StringBuffer("");

// Get the first 32KB of the job
char buffer[] = new char[8192];
int intTotalBytesRead = 0;
do
{
  intBytesRead = br.read(buffer);
  if (intBytesRead == -1)
    break;

  intTotalBytesRead += intBytesRead;
  sb.append(buffer, 0, intBytesRead);
} while (intTotalBytesRead < 32767);

System.err.println("Totaal gelezen bytes=" + intTotalBytesRead);

// Converteer string buffer ff naar string
strTemp = sb.toString();

// Schrijf string naar file

De file sizes zijn exact gelijk, maar een aantal bytes worden omgezet naar andere bytes, bijvoorbeeld: 81 wordt 3F, 9D wordt 3F en nog een aantal bytes worden allemaal naar 3F omgezet.

Ik heb een idee dat dit met de encoding te maken heeft, maar ik heb helaas nog geen oplossing gevonden.

Kan iemand mij please verder helpen :?

It’s nice to be important but it’s more important to be nice


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
Is de file die je inleest ook Unicode ge-encoded :?

  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
Op dinsdag 11 juni 2002 11:23 schreef Glimi het volgende:
Is de file die je inleest ook Unicode ge-encoded :?
Nope. Het is een binair bestand.
Ik wil eigenlijk helemaal geen encoding gebruiken, maar een exacte binare kopie maken van het bestand dat ik binnenkrijg.

Ik heb geprobeerd om ASCII als encoding op te geven, maar dan nog worden bepaalde bytes omgezet :?
Voorheen werkte ik met een byte array en een BufferedInputStream en dat werkte wel.

Als je de reden wilt weten dat ik ben overgestapt naar een InputStreamReader moet je ff de posts hiervoor lezen in dit topic.

It’s nice to be important but it’s more important to be nice


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
Op dinsdag 11 juni 2002 11:27 schreef JonkieXL het volgende:
Nope. Het is een binair bestand.
Ik wil eigenlijk helemaal geen encoding gebruiken, maar een exacte binare kopie maken van het bestand dat ik binnenkrijg.
Waarom lees je het dan als char's in? Het zijn toch gewoon bytes, ook al vormen ze toevallig letters.

Ook praat je over bytes overal en gebruik je chars. Een char is niet een byte maar 2 bytes (Unicode), dus ik ben een beetje de draad kwijt

  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
Op dinsdag 11 juni 2002 11:30 schreef Glimi het volgende:
Waarom lees je het dan als char's in? Het zijn toch gewoon bytes, ook al vormen ze toevallig letters.

Ook praat je over bytes overal en gebruik je chars. Een char is niet een byte maar 2 bytes (Unicode), dus ik ben een beetje de draad kwijt
Heb je helemaal gelijk in. Ik gebruikte ook eerst bytes en dat ging goed. Echter ik ben overgestapt naar Chars omdat dat makkelijker om te zetten is naar een string.

Mijn vorige code was:
code:
1
2
3
4
5
6
7
byte jobBytes[] = new byte[1024];
while((intBytesRead = bufferedinputstream.read(jobBytes)) > 0)
{
  // Place de bytes read in a string 
  strTemp = new String(jobBytes, 0, intBytesRead);
  sb.append(strTemp);
}

Echter de regel:
strTemp = new String(jobBytes, 0, intBytesRead);

leverde nogal wat performance verlies dus vandaar dat ik met char[] wilde gaan proberen. Een char array kan je namelijk meteen toevoegen aan een stringbuffer.

It’s nice to be important but it’s more important to be nice


Verwijderd

Wat voor manipulatie wil je precies met die data doen? Anders schrijf je het geheel eerst naar een temp file...
Je kunt natuurlijk ook zelf even een ByteBuffer class maken

  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
Op dinsdag 11 juni 2002 12:25 schreef tijnbraun het volgende:
Wat voor manipulatie wil je precies met die data doen? Anders schrijf je het geheel eerst naar een temp file...
Je kunt natuurlijk ook zelf even een ByteBuffer class maken
Uit de bytes moet ik een reeks karakters verwijderen (die op een variabele positie kunnen staan).
Ik heb dus een String object nodig, omdat ik anders een heleboel methods zoals IndexOf etc. niet ter beschikking heb.

It’s nice to be important but it’s more important to be nice


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Als je er een String van wilt maken moet het een encoding hebben. Anders kan het nooit gerepresenteerd worden als een (unicode) String.

Als de bytes simpelweg een vreemde encoding hebben moet je een passende encoding zoeken, een eigen encoding schrijven en als dat beide niet mogelijk is simpelweg geen String gebruiken...

Een String is namelijk geen serie van bytes, maar een tekst in Unicode encoding.

Ik begreep uit je gebruik van Strings dat je gewoon een tekst in aan het lezen bent, maar als dat niet het geval is gaat mijn advies niet op.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
Op dinsdag 11 juni 2002 12:56 schreef mbravenboer het volgende:
Als je er een String van wilt maken moet het een encoding hebben. Anders kan het nooit gerepresenteerd worden als een (unicode) String.

Als de bytes simpelweg een vreemde encoding hebben moet je een passende encoding zoeken, een eigen encoding schrijven en als dat beide niet mogelijk is simpelweg geen String gebruiken...

Een String is namelijk geen serie van bytes, maar een tekst in Unicode encoding.

Ik begreep uit je gebruik van Strings dat je gewoon een tekst in aan het lezen bent, maar als dat niet het geval is gaat mijn advies niet op.
Het is geen 'gewone' stream. Er komen ook ASCII waarden boven de 200 in voor. Maar het is in principe gewoon een ASCII file.

Het probleem is dus dat ik geen passende encoding kan vinden. Ik heb ook ASCII als encoding geprobeerd, maar dan worden toch nog een aantal bytes omgezet.

Ik wil wel proberen om alle manipulatie via het byte array te doen, maar dat gaat denk ik een stuk lastiger worden dan manipulatie via een String object.

It’s nice to be important but it’s more important to be nice


  • paulh
  • Registratie: Juli 1999
  • Laatst online: 22-06 15:30
Soms wil het ook nog wel eens helpen de Garbage Collector een trap te geven met System.gc().

Het is wel geen garantie dat de garbage collector opgestart wordt. Je moet het zien als een vriendelijk verzoek.

[ZwareMetalen.com] - [Kom in aktie tegen de CO2 maffia]


Verwijderd

Als je niet de goede encoding kan vinden kan je misschien toch beter een eigen ByteBuffer maken (kijk een naar de StringBuffer class course file als voorbeeld)... hieraan kan je dan de benodige functies toevoegen voor byte manipulatie

  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
Oke mensen ik heb het opgelost.
Ik heb bij het maken van een nieuwe string object
ISO8859_1 opgegeven.
Dat is geloof ik ook de standaard encoding die gebruikt wordt in Windows.

Dus ik heb bij het maken van mijn string object de encoding opgegeven als volgt:
strTemp=new String(jobBytes, 0, intBytesRead, "ISO8859_1");

It’s nice to be important but it’s more important to be nice


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik ben niet heel erg goed thuis in al de encodings en charsets, maar volgens mij zou UTF-8 dan wellicht moeten werken...

Als je trouwens echt een performance implementatie nodig hebt moet je eens naar de New IO api kijken en een blik werpen of ByteBuffers, channels en CharsetDecoders :9~ .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
JonkieXL: Ik heb bij het maken van een nieuwe string object ISO8859_1 opgegeven.
Ah mooi :) .

Je kan de Reader oplossing (met dus een betere performance) ook werkend krijgen als je aan de InputStreamReader deze zelfde encoding meegeeft.

Je kan in 1.4 ook gelijk een Charset meegeven, wat netter en duidelijker is:
code:
1
new InputStreamReader(InputStream in, Charset cs)

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • pjonk
  • Registratie: November 2000
  • Laatst online: 29-12-2025
Het heeft me een hoop bloed en zweet gekost, maar uiteindelijk dus toch nog eruit gekomen.
Bedankt voor alle hulp.

It’s nice to be important but it’s more important to be nice

Pagina: 1