Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

ClassLoader pandan u .NET-u

[es] :: .NET :: ClassLoader pandan u .NET-u

[ Pregleda: 2247 | Odgovora: 6 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

river
System Architect

Član broj: 12566
Poruke: 62
157.161.141.*



+1 Profil

icon ClassLoader pandan u .NET-u24.01.2004. u 19:45 - pre 246 meseci
Kompanija u kojoj radim trenutno valorizuje .NET framework. Do sada smo
radili u C++ - u i Javi, a sada eto silom prilika vikend provodim citajuci
"Applied MS .NET programming". Sa sintaksom C#-a sam upoznat jer od pojave
..NET-a pratim razne �lanke, medjutim nikada do sada nisam podrobnije ulazio
u strukturu same .NET biblioteke ili ti Framework Class Library.

E sad citajuci knjigu naisao sam na mnoge paralele izmedju .NET-a i Jave,
medjutim jedno mi nije jasno. U knjizi sam nasao da je AppDomain jedina
celina koja se moze dinamicki ucitati i unloadovati. Ovo me je navelo na
pomisao da .NET nema pandan ClassLoader-u. Da li je tacno ako kazem da je u
..NET-u nemoguce u runtime-u ucitati tipove (klasse), koristiti ih, a zatim
zaboraviti na njih i naterati GC da ih pokupi.
Nesto tako je moguce koriscenjem AppDomain-a kao CL-a u javi, ali koriscenje
klasa iz drugog domena povlaci za sobom penal marshaling-a (znaci neefikasno
je). Jedan moj kolega kaze da je mozda razlog ove moje zabune taj sto je
knjiga pisana za 1.0 verziju .NET-a pa vas ja pitam da li je nesto
promenjeno u 1.1 verziji.

Jos jedno pitanje na koje sam naisao na nekom suparnickom Java sajtu. Tamo
kazu da .NET nema pravi pandan RMI-u u javi. E sad ja sam svojim ocima video
Remoting namespace u netu, ali nisam nigde video mogucnost da automatski
downloaduje implementacije koje ne postoje na lokalnoj VM.

Bio bih puno zahvalan nekom ko poznaje dobro .NET na odgovoru i na uput za
best-pratice in .NET, zato sto ja mozda samo razmisljam na Java nacin kada
trazim ClassLoader, mozda se to u .NET-u radi drugacije.


Everything should be made as simple as possible, but not simpler. - AA
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
..ndg-pm4-2.dialup.nethere.net



+6 Profil

icon Re: ClassLoader pandan u .NET-u25.01.2004. u 03:49 - pre 246 meseci
Citat:
river:
U knjizi sam nasao da je AppDomain jedina
celina koja se moze dinamicki ucitati i unloadovati. Ovo me je navelo na
pomisao da .NET nema pandan ClassLoader-u. Da li je tacno ako kazem da je u
..NET-u nemoguce u runtime-u ucitati tipove (klasse), koristiti ih, a zatim
zaboraviti na njih i naterati GC da ih pokupi.


Nije tačno. Moguće je dinamički učitavati assemblies (koji su u stvari "celina koja se može dinamički učitati i unloadovati").

Pogledaj System.Reflection.Assembly klasu, posebno metode Load*, kao i CreateInstance.



 
Odgovor na temu

river
System Architect

Član broj: 12566
Poruke: 62
157.161.141.*



+1 Profil

icon Re: ClassLoader pandan u .NET-u25.01.2004. u 12:36 - pre 246 meseci
Da ali assembly ucitan load metodom se ucitava u kontekst pozivajuceg
AppDomain-a, a ne postoji metoda Unload za assembly, nego je jedino moguce
unloadovati ceo appdomain.

Meni je potreban mehanizam kojim cu ja da u moj trenutni AppDomain ucitam
neki assembly koji je nepoznat za vreme kompajliranja. Ok ovo moze da se
izvede System.Reflection.Assembly.Load* methodom.

Zatim ja hocu da koristim klase iz ovog assembly-a. Ok i za to si dao
objasnjenje, ali sada ostaje problem sto su mi svi tipovi iz assemblia
ostali ucitani. Ja zaboravim na assemby (obrisem pointer) ali je on ipak u
memoriji. Znaci nema metoda Assembly.Unload ili slicno.

Ovo pitam zato sto 90% naseg software-a sada iskoriscava mogucnost da
koristimo razne jar fajlove i da ih ucitavamo i brisemo iz memorijie
dinamicki. Ovo je potrebno posto nasi serveri moraju da budu 99.99% on-line,
a nova pravila procesiranja se dodaju dnevno, nekada i vise nego jedanput
dnevno. U takvoj situaciji posle nekih 20 dana rada servera vise ne bi bilo
slobodne memorije ukoliko se svi Types iz svih Rules assemblia cuvaju u
memoriji dok AppDomain proces zivi. U stvari sa nasom implementacijom u Javi
se desilo nesto slicno, ali smo onda naucili da treba da se oslobodimo
ClassLoadera i kada ga GC pokupi onda on oslobodi svu memoriju koja je
rezervisana za klase iz objekata koje su ucitani tim Loaderom.

Ti kazes da su assemblys celina koja se moze ucitati dinamicki i sa time se
slazem, ali kako ga unloadovati. Assemby i sve tipove koji su definisani u
njemu. Ja sam u dokumentaciji nasao da je moguce jedino ukoliko se unloaduje
AppDomain, ali opet mozda je problem u tome sto ja ispred sebe imam
dokumentaciju za .NET 1.0. Da li je nesto promenjeno po tom pitanju u 1.1.
Da li je dodata metoda Assembly.Unload*. A ukoliko i hocu da koristim
AppDomaine da bih oslobodio svu memoriju koju zauzima assemby, onda moram da
placam marshaling za svaki metod koji pozivam iz server AppDomain-a u
assemby AppDomain.

Dakle da rezimiram kako je moguce iz trenutnog AppDomain-a unloadovati
Assembly koji je prethodno dinamicki ucitan.


Everything should be made as simple as possible, but not simpler. - AA
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
..ndg-pm4-2.dialup.nethere.net



+6 Profil

icon Re: ClassLoader pandan u .NET-u25.01.2004. u 19:40 - pre 246 meseci
Ups! U pravu si. Ništa od unloadovanja assembly-ja i .NET 1.1 ne donosi ništa novo u tom pogledu.

Interesantna rasprava na tu temu:

http://www.dotnet247.com/247reference/msgs/38/193854.aspx
 
Odgovor na temu

mmix
Miljan Mitrović
Profesorkin muz
Passau, Deutschland

SuperModerator
Član broj: 17944
Poruke: 6042



+4631 Profil

icon Re: ClassLoader pandan u .NET-u25.01.2004. u 19:49 - pre 246 meseci
Assembly.Unload ti uopšte nije potreban i u krajnjoj instanci narušava koncept managed code-a. AppDomain može da se unload-uje samo zato što je "application boundary" ujedno i "garbage collector boundary". Elem, da bih dokazao da sam u pravu ;), sklopio sam ovo malo parče koda (šta bih inače radio nedeljom popodne :) ). Pošto se assembly (i njegov image) tretira kao tip i samim tim alocira na heapu, onda možemo uraditi i nešto ovako:

Code:
 
using System;
using System.Reflection;

namespace GCCollectIntExample
{
    class MyGCCollectClass
    {
        private const long maxGarbage = 100000;
      
        static void Main()
        {
            MyGCCollectClass myGCCol = new MyGCCollectClass();

            Console.WriteLine("--- Begin");
            Console.WriteLine("Allocated memory is {0}", GC.GetTotalMemory(false));
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));            

            Console.WriteLine("--- Loading assembly");
            Assembly asm;
            asm = Assembly.LoadFile(@"c:\included.dll");
            asm = null;
            Console.WriteLine("--- Loaded");
            Console.WriteLine("Allocated memory is {0}", GC.GetTotalMemory(false));
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));            

            Console.WriteLine("--- Loading and dereferencing {0} times", maxGarbage);
            for(int i = 0; i < maxGarbage; i++)
            {
                // Fill up memory with unused assemblies.
                asm = Assembly.LoadFile(@"c:\included.dll");
                asm = null;
            }
            Console.WriteLine("--- Done");
            Console.WriteLine("Allocated memory is {0}", GC.GetTotalMemory(false));
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));            

            Console.WriteLine("--- Full collect of all generations");
            GC.Collect();
            Console.WriteLine("--- Done");
            Console.WriteLine("Allocated memory is {0}", GC.GetTotalMemory(false));
            Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));            
            Console.Read();
        }
    }
}


Za 10 iteracija rezultat je:
Code:
--- Begin
Allocated memory is 24496
Generation: 0
--- Loading assembly
--- Loaded
Allocated memory is 40880
Generation: 0
--- Loading and dereferencing 10 times
--- Done
Allocated memory is 49072
Generation: 0
--- Full collect of all generations
--- Done
Allocated memory is 30448
Generation: 1


Dok je za 100000 iteracija (što je trajalo sveukupno oko 20s):
Code:
--- Begin
Allocated memory is 24496
Generation: 0
--- Loading assembly
--- Loaded
Allocated memory is 40880
Generation: 0
--- Loading and dereferencing 100000 times
--- Done
Allocated memory is 310168
Generation: 1
--- Full collect of all generations
--- Done
Allocated memory is 30632
Generation: 2


Iako se ne može napraviti neka hirurški precizna analiza neke stvari se mogu zaključiti iz ovoga. Ali kao prvo malo pojašnjenje oko "Generation: x", ovde program ispisuje koliko puta je GC pokušao da collect-uje myGCCol, instancu naše klase za koju smo sigurni da je na heap-u kao strong reference. Pošto collect propada (jer je instanca još "živa") GC odlučuje da je referenca verovatno tu da ostane i promoviše je u sledeću generaciju. Indirektno ako je Generation prešao iz 0 u 1 to znači da je GC bar jednom pokušao collect nad nultom generacijom. Zgodno za naše potrebe. Treba i napomenuti da je sistemski alocirana memorija na kraju prvog primera bila 6592kb, a na kraju drugog 7022kb (čak sam i stavljao ručno collect iza svakog load, pa je na kraju test11.exe imao 100kb sistemski alocirane memorije)

Elem:
1. Inicijalno je alocirano 24496 bajtova, tu su neke gluposti i naš myGCCol :)
2. Prvi Assembly.Load podiže alokaciju za oko 16kb (toliko je otprilike velik i sam included.dll), za sada je sve ok
3. Svako sledeće učitavanje inkrementalno podiže alokaciju za otprilike 8kb na svakih 10 učitavanja, odakle sledi:
3a. Assembly koji je već u memoriji ne učitava se dvaputa ako ne mora
3b. Assembly klasa za potrebe 3a verovano održava neku WeakReference tabelu čije održavanje dovodi do ovog minimalnog povećanja alocirane memorije
4. U prvom primeru posle 10 učitavanja generation je 0 (što znači da GC nije nijednom pokušao da počisti heap)
5. U drugom primeru posle 100000 učitavanja alocirano je nekih 300kb, ali je generation = 1, što znači da je bar jednom GC počistio samo nultu generaciju da napravi mesta, tako da nam tih 300kb ne znači mnogo
6. Ali ;), posle GC.Collect, kad se GCu naloži da počisti sve generacije (što se vidi iz povećanja generation vrednosti), alocirana memorija u oba slučaja pada na oko 30k, što znači:
6a. U memoriji više nema nijedne instance included.dll assembly-a, inače bi na kraju moralo biti alocirano bar 40k.

Dakle, ono što ti treba da uradiš je da nulluješ sve reference koje direktno i indirektno pokazuju na assembly i da pustiš GC da radi svoj posao. Ti možeš da ga nateraš da pokupi mrtve assembly-e iz memeorije sa GC.Collect, ali to može degradirati performase, pošto u trenutku kad pozoveš GC.Collect SVE žive instance bivaju promovisane u sledeću generaciju, pa bi dosta instanci koje bi kasnije bile mrtve i u generaciji 0 (dakle collectable sa Collect(0)) biće u generaciji 1 i biće izbačene mnogo kasnije (kad baš zagusti pa collect(0) ne može da pribavi dovoljno memorije pa GC mora da uradi i Collect(1)).

Inače se zbog ovakvog ponašanja skoro sve .NET aplikacije ponašaju kao da su bagovite i da imaju "leak" probleme. Jednom sam pratio windows service koji je 10 (deset) dana konstantno punio memoriju po malo, dok 10-og dana nije sa svojih 100 linija koda napunio 50mb memorije. Onda je nešto kvrcnulo u runtimeu i GC je odradio Collect(0) i program je oslobodio 90% alocirane memorije i spao na 5mb. Znači nikada ne znaš kad će GC da uradi Collect(0), ako imaš dovoljno memorije mogu i meseci da prođu :), ali isto tako čim zagusti i ponestane memorije ume i Collect(2) da odradi i da istrese sve mrtve instance (trenutno instance mogu da doguraju samo do druge generacije, svaka sledeća provera ostavlja ga tu gde je (u drugoj). Ako mene pitate, veoma dobro osmišljen sistem.

Sloba je za 12 godina promenio antropološki kod srpskog naroda. On je od jednog naroda koji je bio veseo, pomalo površan, od jednog naroda koji je bio znatiželjan, koji je voleo da vidi, da putuje, da upozna,
od naroda koji je bio kosmopolitski napravio narod koji je namršten, mrzovoljan, sumnjicav, zaplašen, narod koji se stalno nešto žali, kome je stalno neko kriv… - Z.Đinđić
 
Odgovor na temu

havramm
Miroslav Havram
Software Developer / Engineer
Beograd

Član broj: 4603
Poruke: 255
*.proxy.cg.yu



Profil

icon Re: ClassLoader pandan u .NET-u25.01.2004. u 21:39 - pre 246 meseci
Isprobavao sam ovaj tvoj primer i dosao do sledecih rezultata (ucitavani assembly ima 13824 bajtova):

10x
Code:

--- Begin
Allocated memory is 18408
Generation: 0
--- Loading assembly
--- Loaded
Allocated memory is 22504
Generation: 0
--- Loading and dereferencing 10 times
--- Done
Allocated memory is 30696
Generation: 0
--- Full collect of all generations
--- Done
Allocated memory is 28312
Generation: 1


1Mx
Code:

--- Begin
Allocated memory is 18408
Generation: 0
--- Loading assembly
--- Loaded
Allocated memory is 22504
Generation: 0
--- Loading and dereferencing 1000000 times
--- Done
Allocated memory is 180220
Generation: 1
--- Full collect of all generations
--- Done
Allocated memory is 28300
Generation: 2



Citat:

2. Prvi Assembly.Load podiže alokaciju za oko 16kb (toliko je otprilike velik i sam included.dll), za sada je sve ok

Moj assembly je velik oko 13k, a nakon prvog ucitavanja nivo se podize za samo oko 4k.

Citat:

6. Ali ;), posle GC.Collect, kad se GCu naloži da pocisti sve generacije (što se vidi iz povecanja generation vrednosti), alocirana memorija u oba slucaja pada na oko 30k, što znaci:
6a. U memoriji više nema nijedne instance included.dll assembly-a, inace bi na kraju moralo biti alocirano bar 40k.

U oba slucaja kod mene alocirana memorija je pala na oko 28k, sto znaci da tamo negde jos uvek nesto zivi (osim myGCCol)...
If it's a girl then they're gonna call it Sigourney, after an actress. If it's a boy, then they're gonna call it Rodney, after Dave!
 
Odgovor na temu

river
System Architect

Član broj: 12566
Poruke: 62
157.161.141.*



+1 Profil

icon Re: ClassLoader pandan u .NET-u26.01.2004. u 00:56 - pre 246 meseci
Citat:
*Dragi Tata:*
Interesantna rasprava na tu temu:

http://www.dotnet247.com/247reference/msgs/38/193854.aspx


Da vrlo interesantna tema. Ipak moram da konstantujem da sam se nadao da sam
ja nesto prevideo, i da postoji neki drugi nacin od koriscenja AppDomain-a.
Napravicu par testova na temu performansi i produktivnosti koda kada se
koristi AppDomain u tu svrhu pa cu objaviti rezultate. Samo je tesko
ocekivati da ce performanse da budu zadovoljavajuce za neke moje trenutne
projekte, moguce je da ipak ima dosta applikacija gde je penal samog posla
toliki da se ne mora misliti mnogo o penalu marshaling-a jer je on u ukupnoj
prici zanemarljiv.

Citat:
*mmix:*
Assembly.Unload ti uop�te nije potreban i u krajnjoj instanci naru�ava
koncept managed code-a.

Java ovo ima, a ona je isto managed code. Jedino je verovatno da postoje
neke interne stvari koje predstavljaju problem pri implementaciji ovoga.
Pogledaj link koji je Dragi Tata ostavio.

Citat:
*mmix:*
Assembly koji je ve� u memoriji ne u�itava se dvaputa ako ne mora

Ovo je vrlo tacno i vrlo logicno posto se radi o istom assembliu u istom
AppDomain-u. Da si ucitavao svaki od assemblia u novi AppDomain dobio bi
drugacije rezultate. Ovo je upravo ono sto mene muci..

Citat:
*mmix:*
6. Ali ;), posle GC.Collect, kad se GCu nalo�i da po�isti sve generacije
(�to se vidi iz pove�anja generation vrednosti), alocirana memorija u oba
slu�aja pada na oko 30k, �to zna�i:
6a. U memoriji vi�e nema nijedne instance included.dll assembly-a, ina�e bi
na kraju moralo biti alocirano bar 40k.

Da li je klasa u memoriji ostala zato sto je GC odlucio da ima dovoljno
memorije te je bolje da saceka sa collectom je totalno irelevantno za nasu
pricu. Taj kod je u memoriji , ali je on "mrtav kod". Tako da ce biti
pokupljen kad tad. Normalno je da ce biti pokupljen pre nego sto CLR ostane
bez memorije. Medjutim oko 6a nemogu da se slozim, a mozes i da se uveris
ako na kraj svog listinga dodas:
Code:

Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < asms.Length; i++) {

Console.WriteLine(asms[i].ToString());

}

Console.ReadLine();



videces da je included.dll ostao u memoriji.


Everything should be made as simple as possible, but not simpler. - AA
 
Odgovor na temu

[es] :: .NET :: ClassLoader pandan u .NET-u

[ Pregleda: 2247 | Odgovora: 6 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.