Autor Wątek: Pyt z Javy (2)  (Przeczytany 4605 razy)

Offline rhdbisgrt

  • Użytkownik

# Listopad 28, 2012, 13:27:18
Mam pytanie dot jawy. Dosyc slabo znam jawe (ale ze jako tako znam tematy z ogolnego programowania to jak trzeba cos tam moge sklecic) i ostatnio sie jej wlasnie przygladam, dokonujac przy tym paru obserwacji (dosyc banalnych zreszta zapewne) powstaje przy tym dla mnie przy okazji tego studiowania javy zasadnicze pytanie :

 Czy te rozmaite wysokopoziomowe myki tj konkretnie widze na dany moment dwa

1) rozmaite 'nie zwalnianie' obiektow,
2) rozmaite 'przekazywanie' (i wrappowanie) obiektow itp

sa w jawie 'bezpieczne'?

Tj mam na mysli wszelkie sytuacje gdzie nie przejmuje sie zwalnianiem  czegokolwiek

(np w danej konkretnej sytuacji mam  tablice[][] z pixelami ale zeby to wyswietlic musze to opakowac w image pozniej wyswietlic, poniewaz  robie to w kazdej ramce to po prostu tworze nowy image za kazdym razem nie przejmujac sie starym i nie zwalniajac go)

podobnie jest z przekazywaniem i robieniem najrozmaitrzej sieczki wrapperow, powiedzmy ze mam jeden oryginalny kawalek danych z pixelami, czy pakujac to w najrozmaitsze obiekty po drodze zeby cos zrobic wyswietlic, zapisac na dysk, itp mam gwarancje ze dane te nie beda topornie kopiowane tylko ze to wszystko beda lekkie operacje?

tj czy jawie mozna zaufac ze nmie przejmujac sie problemem zwalniania i problemem przekazywania i wrappowania poradzi sobie ona tj nie wykona jakichs masywnych duplikatow (albo jakichs innych pokrewnych zarzynek). mam nadzieje ze moje pytanie jest zrozumiale, a jesli nie i jawa moze wykonac taką zarzynkę to prosilbym najlepiej o konkretny przyklad takiej zarzyny ze strony jawy. tnx

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Shusty

  • Użytkownik

# Listopad 28, 2012, 14:12:29
W Javie też można doprowadzić do wycieku pamięci, ale wystarczy troszkę pomyśleć. Ogólnie nie powinieneś się tym przejmować, bo nie tak łatwo do tego doprowadzić. Po to Java i C# ma GC, by odciążyć programistę. Jeśli do obiektu utracimy referencję (przypiszemy jej nulla, wyjdziemy poza zasięg istnienia referencji itd.) to Java przeszukuje drzewko o odśmieca wszystko do czego nie masz już dostępu. W Javie są typy proste (int, float etc.  String już nie!), reszta to typy złożone, do których się odwołujesz referencjami (taki wykastrowany wskaźnik z C++), obiekty więc nie wędrują w pamięci i się nie duplikują jeśli przypiszesz ten sam obiekt 10 referencjom no nie? Bo one tylko wskazują na obiekt.   

Sprubój np. zrobić coś takiego:
String s1= new String("asd");
String s2= new String("asd");
if(s1==s2) System.out.println("równe");
else System.out.println("różne");

s1=s2;
if(s1==s2) System.out.println("równe");
else System.out.println("różne");

Taki mały eksperymencik co dużo wyjaśni. Typy proste oczywiście można opakować i mamy Klasy typu Integer etc.

Offline Kos

  • Użytkownik
    • kos.gd

# Listopad 28, 2012, 14:38:25
1) Niezwalnianie - obiekty w javie koncepcyjnie mają niezdefiniowany czas życia. Jak go stworzysz, to on sobie "jest". (Implementacja zwolni pamięć po nim wtedy, gdy będzie to możliwe bez wpływania na zachowanie programu.)

2) Przekazywanie - tutaj nie ma problemu, bo przekazujesz tylko referencje do obiektów. Ten dziwny stwór pod tytułem "kopiowanie obiektów, gdy tylko je chcesz gdzieś przekazać", to rzecz bardzo dziwna z punktu widzenia OOP i dość specyficzna dla C++. W Javie obiekty się "kopiują" tylko wtedy, jak to zrobisz sam, np. przez .clone().

Te same uwagi możesz odnieść do większości języków obiektowych, Pythona, C#, Javascriptu...

Offline Cocomide

  • Użytkownik

# Listopad 28, 2012, 14:43:36
Może nie opowiem na przykładzie Java, bardziej C# ale jestem pewien, że to działa tak samo.
Do końca nie ufam GC, nie dlatego, że się boję, że nie zwróci mi pamięci jak zgubie obiekt - bardziej boje się, że za bardzo mu zaufam. Kiedy mam do dyspozycji GC myślę bardziej globalnie. Nie zastanawiam się jak opakować każdy ekran aplikacji żeby zwalniał mi pamięć po poprzednim, to prowadzi do zastanowienia się - a może wszystko będę trzymał zawsze w pamięci? I tak z gra w c++ zjadająca około 100 MB RAM, przeportowana na C# działa szybciej, ale zjada 1GB RAM. Wiem, że to pewnie przez brak doświadczenia z wysokopoziomowymi językami - to po prostu kusi :).

GC działa, na tyle dobrze, że się zapomina o przydzielaniu pamięci. Dlatego zawsze warto globalne (ale nie globalne, oop FTW) funkcjonalności czyścić jeżeli trzeba. Funkcja Dispose() zawsze się przydaje np. przy zwalnianiu Assetów w listach :)

Offline rhdbisgrt

  • Użytkownik

# Listopad 28, 2012, 14:54:53
1) Niezwalnianie - obiekty w javie koncepcyjnie mają niezdefiniowany czas życia. Jak go stworzysz, to on sobie "jest". (Implementacja zwolni pamięć po nim wtedy, gdy będzie to możliwe bez wpływania na zachowanie programu.)

2) Przekazywanie - tutaj nie ma problemu, bo przekazujesz tylko referencje do obiektów. Ten dziwny stwór pod tytułem "kopiowanie obiektów, gdy tylko je chcesz gdzieś przekazać", to rzecz bardzo dziwna z punktu widzenia OOP i dość specyficzna dla C++. W Javie obiekty się "kopiują" tylko wtedy, jak to zrobisz sam, np. przez .clone().

Te same uwagi możesz odnieść do większości języków obiektowych, Pythona, C#, Javascriptu...

ad 1

spox tyle ze jest jeszcze problem wydajnosci,
wez np takie cos

int pixels[500][500];

wygenerujObraz(pixels);

for(int i=0; i<10000; i++)
{
  Image image = new Image(pixels);
}

tutaj 10 tys razy tworze obiekt, ok 10 tys bedzie on tez odlozony do zniszczenia - czy to jest niezauwazalnie szybkie?

ad 2

spox, to dobrze tyle ze javowe api umozliwia rozne skomplikowane kombinacje, czy mam gwarancje ze w srodku nie ma tych clone ?  Byc moze pewne metody  moga tego wymagac i uzywajac tego skazuje sie na
zarzyny, gdy tymczasem kombinujac jak to zrobic z reki mozna by tego uniknac - tego dotyczy to pytanie,
czy takie sytuacje sa czy ich nie ma i ZAWSZE jest lekko i szybko?

(NIe mam jakos jasnosci co do tych spraw, takie pietrowe pakowanie wyglada na wolne, ale ew moglbym zaufac twierdzeniu ze jest szybko, tyle ze powinno byc ono chyba jakos uwiarygodnione czy uzasadnione (bo jak nie to raz moze byc wolno raz szybko i nie wiadomo jak to odroznic i sie polapac itp)
 


« Ostatnia zmiana: Listopad 28, 2012, 15:01:41 wysłana przez rhdbisgrt »

Offline Shusty

  • Użytkownik

# Listopad 28, 2012, 14:58:15
@Cocomide trochę przesadzasz. Programy w C#, Java się szybciej pisze, nie są wcale o wiele wolniejsze od C++, czasami nawet porównywalne i szybsze, fakt że RAMu zabierają więcej trochę, ale bez przesady, Duży skok zapotrzebowania na pamięć jest tylko podczas startu maszyny wirtualnej. W C#, Javie można doprowadzić do wycieków pamięci a jakże. 

Są i tacy co używają Disposable, ale robią bez żadnej uzasadnionej potrzeby, bo myślą, że mają w Javie desktruktor, a porównywanie tych dwóch rzeczy już na samym początku jest kompletną bzdurą, nie mówiąc o tym, żeby zapobiegawczo nulle ot tak powstawiać pod referencje w klasie i wywołać dispose głębiej. Kompletna bzdura i nie dość że nic pożytecznego to nie da, to prędzej zaszkodzi szybkością działania, jak używanie obsługi wyjątków, które lecą często zamiast posprawdzać wcześniej ifami nulle, size itd. co jest niesamowicie szybsze. wyjątków używa się tylko jeśli zakładamy że one nie polecą, ale kiedyś tam może się zdarzyć.

Co do dispose, używamy tylko (i powinniśmy), jeśli korzystamy z jakichś zasobów, typu strumienie, połączenia z bazami danych, JFrame etc. Wtedy korzystamy z dispose bo trzeba np. pozamykać strumienie, w innych przypadkach nie korzystamy z dispose ani finalize() (nie, nie mówię o tym z obsługi wyjątków).

Offline Shusty

  • Użytkownik

# Listopad 28, 2012, 15:04:53
@rhdbisgrt

Ad1. W C++ miałbyś to samo tylko bezpośrednio byś wywołał szybko destrukcję, Java sobie to usunie, kiedy wg niej będzie najlepszy moment. W C++ też byś dynamicznie new użył więc?

Ad2. Metodę clone trzeba wywołać ręcznie jeśli chce się z niej skorzystać, dodatkowo dany obiekt musi Implementować interfejs Clonable, więc się nie martw że samo Ci się coś zrobi. typy proste to typy proste, a złożone to złożone. Chyba wiesz jak działa referencja/wskaźnik?

Offline Xion

  • Moderator
    • xion.log

  • +1
# Listopad 28, 2012, 15:06:09
Cytuj
mam gwarancje ze dane te nie beda topornie kopiowane tylko ze to wszystko beda lekkie operacje
Nie masz żadnych. Obiekty mogą być wprawdzie nieklonowalne, ale nikt nikomu nie zabroni pobrania całego stanu takiego obiektu i przekazania go do konstruktora nowego obiektu.

Ba, w sumie to nawet jest zalecane. Ponieważ:

(1) obiekty ze zmiennym stanem (mutable state) to prawie czyste zło, zwłaszcza z punktu widzenia współbieżności
(2) tworzenie obiektu to pioruńsko szybka operacja (~nanosekundy)

powszechną praktyką jest tzw. defensywne kopiowanie. Dobrze napisana klasa, która dostaje z zewnątrz obiekt o zmiennym stanie, w konstruktorze zrobi jego kopię. Robi się to po to, by zabezpieczyć się przez zmianą stanu tego obiektu, co automatycznie zmieniłoby też stan obiektu go opakowującego, gdybyśmy tylko zapisali doń referencję.

Cytuj
W Javie też można doprowadzić do wycieku pamięci, ale wystarczy troszkę pomyśleć. Ogólnie nie powinieneś się tym przejmować, bo nie tak łatwo do tego doprowadzić.
"Skąd wiesz że przestępstwo doskonałe nie istnieje, skoro z definicji nie mógłbyś wiedzieć, że zostało popełnione?"

W Javie całkiem łatwo doprowadzić do wycieku pamięci: wystarczy "zgubić" gdzieś nadmiarową referencję do obiektu, co jest zupełnie możliwe bo nie wszystkie relacje między obiektami widać w kodzie. Pisałem kiedyś artykuł na ten temat: http://xion.org.pl/2011/08/26/sprzatanie-smieci-nie-zapobiega-wyciekom/ .

Cytuj
Kiedy mam do dyspozycji GC myślę bardziej globalnie. Nie zastanawiam się jak opakować każdy ekran aplikacji żeby zwalniał mi pamięć po poprzednim, to prowadzi do zastanowienia się - a może wszystko będę trzymał zawsze w pamięci?
Jeśli mówimy o grach, to czy sytuacja nie wygląda właśnie tak, że wszystko trzymamy w pamięci? Unikanie alokacji w głównej pętli jest właściwie konieczne dla zapewnienia płynności renderingu, więc wszystko jest alokowane na początku levelu.

Cytuj
że mają w Javie desktruktor
W Javie nie ma destruktorów, są finalizery. Notabene w C# też są finalizery, tylko geniusze z MS nazwali je destruktorami. -_-

Cytuj
dany obiekt musi Implementować interfejs Clonable
Nie musi (clone() jest metodą klasy Object, nie interfejsu Cloneable). Cloneable to marker do oznacza obiektów dla których Object.clone() rzeczywiście zwraca poprawną kopię. Prawidłowe używanie tego interfejsu należy do dobrych praktyk a nie jest sprawdzane przez kompilator.
« Ostatnia zmiana: Listopad 28, 2012, 15:09:57 wysłana przez Xion »

Offline rhdbisgrt

  • Użytkownik

# Listopad 28, 2012, 15:29:22

powszechną praktyką jest tzw. defensywne kopiowanie. Dobrze napisana klasa, która dostaje z

W sumie wychodzi to na wieki zamęt.. Jesli uzywam sobie
obiektowego api w javie to ogolnie mam zakladac ze tem nie ma kopiowania i ciezkich operacji czy tez nie moge tego zalozyc i jak sie tego dowiedziec? (Zalezaloby mi na takim pisaniu w javie by unikac ciezkich operacji (a ciezka operacja moze tu byc pewnie tylko jakies spore kopiowanie) Czy tez, jesli nie moge sie tego dowiedziec, okazuje sie ze dla programistow javy co sie wykona lakko a co ciezko jest nieodgadnioną niewiadomą ?

Offline 11

  • Użytkownik

  • +2
# Listopad 28, 2012, 15:32:28
Xion dyskretnie chciał ci przekazać: RTFM.

Offline rhdbisgrt

  • Użytkownik

# Listopad 28, 2012, 15:36:04
@rhdbisgrt

Ad1. W C++ miałbyś to samo tylko bezpośrednio byś wywołał szybko destrukcję, Java sobie to usunie, kiedy wg niej będzie najlepszy moment. W C++ też byś dynamicznie new użył więc?


w c nie potrzebuje tego opakowywac w image, byłoby

for(int i=0; i<10000; i++)
{
  blit(pixels);
}

tutaj jest przypominam

for(int i=0; i<10000; i++)
{
  Image image = new Image(pixels);
}

// dalej jest g.drawImage(image)

tutaj zakładam ze moge zalozyc ze to new Image(pixels) jest lekkie male i ze trzyma tylko wskaznik do pixels, tak ze ew by uszlo, ale w ogolnym wypadku martwi mnie
to ze nie moge miec pewnosci ze tam nie ma zadnych
wolnych operacji


Offline rhdbisgrt

  • Użytkownik

# Listopad 28, 2012, 15:50:47
Xion dyskretnie chciał ci przekazać: RTFM.

A gdzie jest taki manual od Javy? Wiem gdzie jest reference do wywolan api ale jakiegos wstepnego i ogolnego zaznajomienia nie znalazlem.

Offline Shusty

  • Użytkownik

# Listopad 28, 2012, 16:35:14
A Image przypadkiem nie jest klasą abstrakcyjną? Wydaje mi się, że tak więc jakim cudem tworzysz jej instancję?

Poza tym:
int pixels[500][500];  //WTF?
« Ostatnia zmiana: Listopad 28, 2012, 16:42:29 wysłana przez Shusty »

Offline Kos

  • Użytkownik
    • kos.gd

# Listopad 28, 2012, 16:46:21

Offline rhdbisgrt

  • Użytkownik

# Listopad 28, 2012, 19:03:33
A Image przypadkiem nie jest klasą abstrakcyjną? Wydaje mi się, że tak więc jakim cudem tworzysz jej instancję?

Poza tym:
int pixels[500][500];  //WTF?

No mozliwe, że jest niedokładnie, Nie o to jednak mi chodziło i chodzi w danym wątku. Pytanie bylo
raczej nt tego czego mozna sie spodziewac i na
ile od takiego javowskiego api i sposobu pisania.
Jawa chyba i tak nie jest taka zla w tych roznych
wzgledach- Applowskie obj-c z tymi ichnimi recznymi
releasami jest chyba jeszcze gorsze, i c# takoż.