wyciek pamięci

0

Witam

mam mały problem z wyciekiem pamięci prosze luknąć na mój kod gdzie robie jakiś błąd? Allocated Objects przy klasie char[] cały czas rośnie w ciągu kilku minut dochodzi do 1miliona. czy przypisanie temp+="test" jest nieprawidłowe?

import java.util.Timer;

public class test3  {
  public static String dane="";

  public static void aktualizacja() {
    String temp="";
    for (int xx=1;xx<=7000;xx++){
         temp+="test";         
    }
    dane=temp;
  }
  public static void main(String [] args) {
    System.out.println("start test3");
    Timer timer1 = new Timer();   test10 timer1_task = new test10();   timer1.schedule (timer1_task, 0, 1000);
  }

}
import java.util.TimerTask;

class test10 extends TimerTask {
    public void run() {
        test3.aktualizacja();
    }
}
0

powinno byc tak:

StringBuilder sb = new StringBuilder();
for (...) {
  sb.append("test");
}
dane = sb.toString();

Kazde przypisanie do zmiennej typu String powoduje utworzenie nowego obiektu = spowolnienie.

0

s = "A", ile = 100000

    public static String powiel(String s,int ile)
    {
        String zwrot="";
        for (int i=1;i<=ile;i++)
        {
            zwrot+=s;
        }
        return zwrot;
    }
    public static String powiel2(String s,int ile)
    {
        StringBuffer zwrot=new StringBuffer("");
        for (int i=1;i<=ile;i++)
        {
            zwrot.append(s);
        }
        return new String(zwrot);
    }

Funkcja powiel2 wykonuje się około 5500 razy szybciej.

0

dziękuję działa o niebo lepiej :) ale martwi mnie jeszcze ze przy obydwu metodach czy to jest StringBuildier czy StringBuffer troszkę obiektów zostaje czy to jest normalne? czy juz nic nie da się z tym zrobić?

import java.util.Timer;

public class test3  {
  public static String dane="";

  public static String powiel()
  {
        String zwrot="";
        for (int i=1;i<=100000;i++)
        {
            zwrot+="test";
        }
        return zwrot;
  }
  public static String powiel2()
  {
        StringBuffer zwrot=new StringBuffer("");
        for (int i=1;i<=100000;i++)
        {
            zwrot.append("test");
        }
        return new String(zwrot);
  }

  public static String powiel3()
  {
        StringBuilder zwrot=new StringBuilder("");
        for (int i=1;i<=100000;i++)
        {
            zwrot.append("test");
        }
        return new String(zwrot);
  }

  public static void main(String [] args) {
    System.out.println("start test3");
    Timer timer1 = new Timer();   test10 timer1_task = new test10();   timer1.schedule (timer1_task, 0, 1000);
  }
}
import java.util.TimerTask;

class test10 extends TimerTask {
    public void run() {
       //test3.dane = test3.powiel2(); //StringBuffer
       test3.dane = test3.powiel3(); //StringBuilder
    }
}
0

Moze tak... jesli na te elementy nic (ani zmienne, ani pola w innych obiektach) nie trzyma referencji, to zostana one z duzym prawdopodobienstwem usuniete po jakims czasie przez GarbageCollectora. Od tego on wlasnie jest i dlatego wlasnie nie ma czegos takiego, jak destruktor w Javie. Bo to nie programista ma sie tu zajmowac oczyszczaniem pamieci, tylko ten GarbageCollector. Wiec jesli Ci cos zostaje w pamieci, ale NIE TRZYMASZ nigdzie referencji do tego, to mozesz uznac, ze wszystko jest ok.

0

Pytanie tylko czy wie ze nie trzyma. To tez musi sprawdzic. Nalepiej jakby sprofilowal ile jest tych char[] i ile cykli GC. Jelsi GC oczyszcza pamiec z nietrzymanych char[] to nie ma problemu, jak napisal przedmowca.
StringBuilder rowniez ma taki problem, tylko na mniejsza skale. Przeciez tam jest bufor na znaki, czyli char[], i jak jest za maly, to jest dokonywana nowa alokacja pamieci, no i stara tablica gdziestam tez przez chwile jest w pamieci. Czyli mozna zauwazyc podobne zachowanie, tylko duzo mniej takich talic powinno byc.

0
mgs_saladin napisał(a)

dziękuję działa o niebo lepiej :) ale martwi mnie jeszcze ze przy obydwu metodach czy to jest StringBuildier czy StringBuffer troszkę obiektów zostaje czy to jest normalne? czy juz nic nie da się z tym zrobić?

W zaleznosci od celu, jaki chcesz osiagnac (czytelnosc czy optymalizacja), mozesz operowac na surowych tablicach char[], np.:

public class Arrays {
	private static final int ITERATIONS = 100000;
	public static final void main(String[] args) {
		String element = "test";
		char[] src = element.toCharArray();
		char[] dst = new char[ITERATIONS*src.length];
		for(int i=0; i<ITERATIONS; i++) {
			System.arraycopy(src, 0, dst, i*src.length, src.length);
		}
	}
}

Taki kod wykona sie kilkukrotnie szybciej niz poprzednie (StringBuffer[]), przy minimalnym wykorzystaniu pamieci, ale i jego czytelnosc drastycznie spada. Dodatkowo, jesli ilosc iteracji jest jest parzysta, mozesz zdublowac operacje w bloku i obciac ilosc powtorzen o polowe.

0
::. napisał(a)

Pytanie tylko czy wie ze nie trzyma. To tez musi sprawdzic. Nalepiej jakby sprofilowal ile jest tych char[] i ile cykli GC. Jelsi GC oczyszcza pamiec z nietrzymanych char[] to nie ma problemu, jak napisal przedmowca.
StringBuilder rowniez ma taki problem, tylko na mniejsza skale. Przeciez tam jest bufor na znaki, czyli char[], i jak jest za maly, to jest dokonywana nowa alokacja pamieci, no i stara tablica gdziestam tez przez chwile jest w pamieci. Czyli mozna zauwazyc podobne zachowanie, tylko duzo mniej takich talic powinno byc.

GC potrafi ustalić gdy nie ma już twardych referencji na obiekt (w tym też na tablice). Jak to robi - poczytaj o implementacji GC używanych w Javie: CMS i Garbage-First.

W celach testowych można wymusić wykonanie GC, ale w prawdziwych programach jest to niezalecane, gdyż JRE samo wie, gdy uruchomić GC.

System.gc();

0

Zupelnie nie zrozumiales mojej wypowiedzi. Wierz mi nie musze czytac jak dziala GC.
O tym czy wie ze nie trzyma - mowilem o autorze tematu.

0

Aha, no i uruchomienia GC nie mozna wymusic, mozna jedynie zglosic request do JVM, do ktorej i tak nalezy ostateczna decyzja.

1 użytkowników online, w tym zalogowanych: 0, gości: 1