Upload
francis-conley
View
81
Download
3
Embed Size (px)
DESCRIPTION
Java Virtual Machine. Things you w anted to know but were afraid to ask about 16 .02.2005 Konstantin Tretjakov Webmedia AS. Mis on “Java”?. The Java Language Java API ( + r untime environment , rt.jar ) The Java Virtual Machine Java Tools ( java, javac, jdb, javap , … ). Kava. JVM - PowerPoint PPT Presentation
Citation preview
Java Virtual MachineThings you wanted to know but were afraid to ask about
16.02.2005
Konstantin Tretjakov
Webmedia AS
Mis on “Java”?
• The Java Language
• Java API (+runtime environment, rt.jar)
• The Java Virtual Machine
• Java Tools (java, javac, jdb, javap, …)
Kava
• JVM
• Classloading
• Security
• Memory, Garbage Collection
JVM
• Abstraktne arvutusmasin
• Tagab– Sõltumatust platvormist
– Turvalisust
– Network-mobility (Applets, RMI, Jini)
• Pole ainus VM, peaaegu iga keele jaoks on tehtud oma virtuaalmasin (P-machine, MaMa, Lisp-machine, ...)
• JVM oli algusest peale loodud praktiliseks kasutamiseks ja on teistest paremini läbi mõeldud paljudes aspektides (mäluhaldus, lõimed, turvalisus, ...).
JVM kui interpretaator
• Lihtsustades, võib öelda et JVM on in-terpretaator, mis täidab vastava bait-koodi:while (still alive) {
fetch next instruction;execute instruction;
}
• Täitmine võib käia mitmes lõimes• Tüüpiline JVM implementatsioon ei ole
“puhtalt” interpretaator. (JIT-compilation)
Näide 1: Sun Java HotSpot VMKoodi üldiselt interpreteeritakse, kuid nendes kohtades, kus tehakse palju tööd (hot spots) koodi kompileeritakse. Kompilaator oskab kasutada run-time statistikat selleks et valida häid optimisatsioone.
On olemas kaks HotSpot VM variatsiooni:
• “Client” (java –client), vaikimisi kasutatav
• “Server” (java –server)
Soovi korral võib paluda koodi ainult interpreteerida võtmega –Xint.
HotSpot “Client” vs “Server”
Client• Kiirem startup
• Kiirem kompileerimine
• Väiksem footprint
• Soovitatud GUI rakendustele
Server• Aeglasem startup
• Rohkem kompileerimist
• Suurem footprint
• Maksimaalne kiirus suurem
• Soovitatud serverrakendustele
Java “Client” ja Java “Server” on sisuliselt kaks erinevat implementatsiooni, mis kasutavad erinevaid JIT kompilaatoreid, erinevaid mäluhaldamis-strateegiaid ning optimeerivad erinevaid asju.
Näide 2: BEA JRockit
• Veel üks JVM implementatsioon• Nagu Sun’i JVM, kompileerib ainult vajalikke
kohti adaptiivselt tagaplaanil.• Huvitav garbage-collectorite valik• Optimeeritud Intel x86 jaoks• Minu kogemuse järgi jooksutab asju kuni 2 korda
kiiremini kui Sun-i JVM, kuid mõnikord teeb kummalisi core-dump-e.
• Tasuta
JVM arhitektuur
Java stacksHeap Memory
(objects) PC registers
Method area
(class data)
Security subsystem
Classloader subsystem
Execution engine
Native interface
Stacks & PC registers
• Iga lõime jaoks on oma PC-register (program counter), mis viitab selles lõimes järgmisena täitmiseks kuuluva instruktsioonile (v.a. juhul kui lõim täidab native-code-i).
• Igal lõimel on oma stack, mis koosneb freimidest. Iga meetodi väljakutse loob uue freimi, meetodist väljumine eemaldab viimase freimi stack-ist.
• Threadi stacki suurust saab määrata optsiooniga –Xss. Sun JVM default on vist 128k. (-Xss128k)*
• Java ei toeta tail-recursion-it, seega stack on alati “täielik”
Stacks & PC registers
Thread 1 Thread 2
PC = 0x2322 PC = 0x4221
Stack StackStack Frame
Stack Frame
Stack Frame
Stack Frame
Stack Frame
Stack Frame
JVM arhitektuur
Java stacksHeap Memory
(objects) PC registers
Method area
(class data)
Security subsystem
Classloader subsystem
Execution engine
Native interface
Kuidas JVM laadib klasse?
• Klasside laadimine toimub Class Loader-ite abil.
• Class loader-ile antakse ette klassi täisnimi, tema ülesandeks on leida vastava klassi implementatsiooni ning laadida seda mällu
• JVM kasutab vaikimisi “system class loader”-it, kuid vajaduse korral võib luua ka oma implementatsiooni.
Class Loaders
• Järgmised lõigud on (peaaegu) samaväärsed:
somepackage.SomeClass obj = new somepackage.SomeClass();
somepackage.SomeClass obj =
(somepackage.SomeClass)Main.class.getClassLoader()
.loadClass(“somepackage.SomeClass”).newInstance();
Class Loaders
• Kohe pärast käivitamist kasutab JVM enda sisseehitatud “bootstrap class loader”-i selleks et laadida süsteemseid klasse (rt.jar).
• Pärast luuakse “system class loader”, mis oskab kasutada CLASSPATH-is antud infot klasside otsimiseks. Ta laadib parameetrina antud peaklassi kõvakettalt ning käivitab teda.
• Iga klass on seotud teda laadinud class loaderiga. Klassi sees kasutatakse seda teiste klasside laadimiseks.
Bootstrap class loader
• Bootstrap class loaderit saab (Sun JVM) puhul konfigureerida parameetritega – –Xbootclasspath:<nimekiri>– -Xbootclasspath/a:<nimekiri>– -Xbootclasspath/p:<nimekiri>
• Seda oleks vaja ainult siis kui soovite ümberdefineerida java.lang.Long vms standardse klassi.
Custom Class Loader
– Kui vaikimisi kasutatav kettalt klasside laadimine ei sobi (võrgust või mujalt klasside laadimine, klasside genereerimine on-the-fly, krüptitud klasside laadimine, jne)
– Nimekonfliktide lahendamiseks (pluginid, mitu rakendust deploy-tud ühes serveris, jne)
– Turvalisuse mõttes
• Custom class loaderit võib vaja minna:
Custom Class Loader
Class CustomClassLoader extends ClassLoader { public Class findClass(String name) { byte[] b = {leia ja laadi klassi andmed} return defineClass(name, b, 0, b.length); }}
...ClassLoader loader = new CustomClassLoader();Object o =
loader.loadClass(“MyClass”).newInstance();...
Class Namespace
• Iga klassiga on seotud tema class loader.– SomeClass.class.getClassLoader()
• Iga klass on üheselt määratud tema täisnime ja tema class loaderi poolt.
• Ühes JVM-is saab kasutada mitu erinevat sama nimega klassi juhul kui nad on laaditud erinevate class loader-ite abil.
• Class loader teab kust klassi laaditi ja kuidas, seda kasutatakse turvalisuse tagamiseks.
Class Loader Hierarchy
• Kui class loader ei oska leida klassi, mida palutakse, küsib ta teda laadinud class loaderi poolt. Niimoodi tekib class loader-ite hierarhia, kus ülemine on system class loader.
• “Vaikimisi” realiseeritud class loaderi klassi laadimise algoritm (meetod loadClass) on tegelikult selline:1. kui klass oli juba laaditud, tagasta seda
2. küsi kas parent class loader oskab seda laadida
3. proovi laadida klassi ise
• Selline järjekord ei anna “juhuslikult” üledefineerida süsteemseid klasse, ning soodustab “ühiste klasside” kasutamist, samas tal on teatud miinused.
Class Loader Hierarchy
Bootstrap Class Loader
System Class Loader
Custom Class Loader
Vaikimisi realisatsioon lubab klassidele “ära joosta”custom class loaderist, see võib olla ebamugav.
Rakendus
JVM
Näide: Plugins
System Class Loader
Application Class Loader
Plugin1 Class Loader Plugin2 Class Loader
Erinevad pluginid võivad sõltumatult kasutada sama nimega klasse
Näide: Firewall Class Loader
System Class Loader
Firewall Class Loader
Application Class Loader
Firewall class loader ei tegele klasside laadimisega vaid päringute filtreerimisega: ta laseb läbi päringud ainult teatud klasside jaoks (näiteks ainult java.*). See isoleerib rakendust soovimatutest klassidest mis olid CLASSPATH-is määratud.
Näide: J2EE rakendusserverSystem Class Loader
Server Class Loader
Application1 Class Loader Application2 Class Loader
Ühe rakenduse erinevatel moodulitel võivad olla erinevad class loaderid. See lubab moduleid redeploy-da ühe kaupa “on-line”, kuid teeb moodulite vahelist suhtlust keerulisemaks.
Module1 Class Loader Module2 Class Loader
Näide: Weblogic App (default)
Application Class Loader
(laadib kõik EJB moodulid)
Selline konfiguratsioon on mugav sest:• Enamasti veebirakendused peavad saama ligi EJB-dele kuid mitte vastupidi• Veebis on hot-redeploy olulisem (JSP-d).
Soovi korral saab konfigureerida class loaderid ka teistmoodi. (weblogic-application.xml)
WebApp1 Class Loader WebApp2 Class Loader
JVM arhitektuur
Java stacksHeap Memory
(objects) PC registers
Method area
(class data)
Security subsystem
Classloader subsystem
Execution engine
Native interface
Security Subsystem
• Java oli algsest peale planeeritud mobiilsete rakenduste loomiseks (näiteks appletid), ning tal on olemas spetsiaalsed vahendid koodi privileegide piiramiseks.
• Kas koodil on lubatud midagi teha või mitte otsustab klass SecurityManager.
• Enne potentsiaalselt ohtliku operatsiooni sooritamist (näiteks faili lugemist) kutsub JVM välja SecurityManageri meetodit checkPermission sobiva parameetriga. Kui tegevus pole lubatud, viskab see meetod SecurityException.
Security Subsystem
• Alguses on JVM Security Manager määramata, rakendus saab teha midaiganes. Security manageri saab määrata kutsudes välja.
System.setSecurityManager(myManager)
• Muidugi võib realiseerida oma security manager, kuid Javaga kaasa tuleb juba päris mõistlik realisatsioon. Seda saab JVM käivitamisel sisse lülitada järgmiselt:
java –Djava.security.manager
Java Security Manager
• Java Security Manager loeb policy faili määratud java.security.policy property abil, s.t.
java –Djava.security.manager –Djava.security.policy=my.policy
• Policy failis on kirjeldatud mis kood saab teha mida.
Policy fail
grant signedBy “trustedparty" {
permission java.io.FilePermission
“/conf/files/*", "read";
};
grant codeBase “file:/my/files/” {
permission java.security.AllPermissions;
};
Stack Inspection
Selleks et kontrollida kas antud turvakriitiline operatsioon on lubatud, Java Security Manager uurib kõiki stack-is olevaid frame-sid, ning veendub et igale stackis oleva meetodile on lubatud seda operatsiooni sooritama. (seda kontrolli sooritab tegelikult klass nimega AccessController)
MainClass.main(..)
EvilClass.evilMethod()
FileInputStream.<init>()
SecurityManager
.checkPermission(…)
AccessController
.checkPermission(…)
Stack
Kuna stackis on olemas EvilClass, kellele faili lugemine pole lubatud, viskab AccessController exception-it
Privileged Execution
• Oletame et Applet tahab luua tekstiakna, selleks kasutab ta JTextBox klassi, mis oskab ekraanile teksti joonistada. Teksti joonistamiseks on vaja fonte, mis asuvad kuskil failis.
• Kuna JTextBox on käivitatud võõra Appleti poolt, pole tal nagu õigust faile lugeda.
• Selles situatsioonis saab JTextBox öelda et ta vajab oma privileege sõltumata sellest kes teda välja kutsus:
AccessController.doPrivileged(new PrivilegedAction() { public Object run() { // Tee mida vaja on kasutades enda privileege } }
• SecurityManager ei uuri stacki “doPrivileged” väljakutsest ülevale• Idee poolest sarnaneb see lähenemine “suid bitiga” Unixis.
JVM arhitektuur
Java stacksHeap Memory
(objects) PC registers
Method area
(class data)
Security subsystem
Classloader subsystem
Execution engine
Native interface
Mälu (Heap)
• Mälus hoitakse:– Loodud objekte
– Vajalikke abistruktuure (klasside metaandmed, jms)
– Konstante (constant pool)
• Mälu suurust saab määrata optsioonidega– -Xms näitab esialgselt reserveeritud mälu suurust– -Xmx näitab mälu ülempiiri.
– Defaults (Intel, umbes): -Xms3m –Xmx64m– Serverrakendustele on soovitatud panna ms = mx
Constant Pool
• Final-muutujad, String literaalid, klasside ja meetodite nimed (Stringidena) hoitakse nn. constant pool-is. See teatud mõttes sarnaneb sümbolite tabeliga teistes keeltes.
• Selle pärast– Parem on kasutada Boolean.valueOf(...) kuid mitte new
Boolean(..)
– Paljukasutatavad Stringid on parem defineerida literaalidena (nad lähevad kohe pool-i) või kasutada String.intern().
– Intern-itud stringid saab võrrelda == abil.– “A” + “b” on kiirem kui new StringBuffer(“A”).append(“b”).
Automatic Memory Management
Javas ei pea mõtlema sellest kes ja millal objekte vabastab:
C++
Obj* o = new Obj();doWork(o);delete o;
Java
doWork(new Obj());
Mõned arvavad et automaatne mäluhaldus on peamine faktor miks Java (VB/C#/PHP/Perl/Haskell/Javascript/...) on mugavam keel milles arendus läheb kiiremini.
Automatic Memory Management
• On erinevaid viise kuidas korraldada automaatset mäluhaldust:– Reference counting
– Garbage collection
– Infinite memory
• JVM ei spetsifitseeri kuidas konkreetselt peab mäluhaldus realiseeritud olema, kuid enamasti kasutatakse prügikoristamis tehnikat.
Garbage Collection
• Objekte luuakse mälus ning ei vabastata kuni mälust puudu pole. Kui mälu “täis saab” teostatakse “prügikoristamist”: läbitakse terve mälu ning vabastatakse need objektid, millele keegi enam ei viida.
• Lokaalsed muutujad ning kõik objektid, millele saab pääseda ligi nende kaudu on “elusad”, kõik ülejäänud on “surnud”.
Näide: Mark & Sweep GC
Stack
a
b
c
d
e
f
loka
alse
d m
uutu
jad
frei
mid
es
Heap
Näide: Mark & Sweep GC
Stack
a
b
c
d
e
f
loka
alse
d m
uutu
jad
frei
mid
es
Heap
Näide: Mark & Sweep GC
Stack
a
b
c
d
e
f
loka
alse
d m
uutu
jad
frei
mid
es
Heap
Generational GC
• Terve mälu koristamine võtab palju aega (proportsionaalselt koristatavate objektide arvuga)
• Saab tähele panna et enamus objekte “sureb noortena”.
• Sun JVM jagab mälu kaheks osaks: osa noorte objektide jaoks (young generation) ja osa vanade jaoks (tenured generation)
• Enamus prügikoristusi toimub young generation-is, need on “väiksed”. Väikest koristust üleelanud objekt liigub “vanade” objektide juurde.
• Kui vanade seas mälu otsas, tehakse “täis” koristus
Sun Java 1.4.2 GC
http://java.sun.com/docs/hotspot/gc1.4.2/
Sun JVM GC Configuration
• Verbose output: -verbose:gc [GC 325407K->83000K(776768K), 0.2300771 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]
• Olulisem parameeter on young generation-i suurus:– -XX:NewRatio=3 tähendab et young:tenured
generationite suuruste vahekord on 1:3
– Client JVM: NewRatio=8
– Server JVM: NewRatio=2
Different Garbage Collectors
• Throughput collector (-XX:+UseParallelGC)
• Concurrent collector
(-XX:+UseConcMarkSweepGC)
• Incremental collector (-Xincgc)
Reference Objects
SoftReference
WeakReference
PhantomReference
http://java.sun.com/developer/technicalArticles/ALT/RefObj/
JVM arhitektuur
Java stacksHeap Memory
(objects) PC registers
Method area
(class data)
Security subsystem
Classloader subsystem
Execution engine
Native interface
JVM arhitektuur
Java stacksHeap Memory
(objects) PC registers
Method area
(class data)
Security subsystem
Classloader subsystem
Execution engine
Native interface
BonusSome random stuff
Bonus Kava
• Lõimed, sünkroniseerimine
• Huvitavaid Java konstruktsioone
• Strings, encodings
Thread-safety
class Swapper {
int a, b;
public void swap() {
int t = a;
a = b;
b = t;
}
}
Thread-safety
class Swapper {
private int a, b;
synchronized public void swap() {
int t = a;
a = b;
b = t;
}
}
Double-Checked Locking
class SomeClass { private Resource resource = null;
public Resource getResource() { if (resource == null) { synchronized { if (resource == null) resource = new Resource(); } } return resource; }
}
http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html
Synchronized Collections
class SomeClass { private Set s = new HashSet();
public void putValue(Object v) { s.put(v);
}
}
Synchronized Collections
class SomeClass { private Set s =
Collections.synchronizedSet(new HashSet());
public void putValue(Object v) { s.put(v);
}
}
Map ja Listi puhul analoogselt.
Huvitavaid Java Konstruktsioone
Initializer
class SomeClass { {
System.out.println(“Hi”);
}
}
Static Initializer
class SomeClass { static {
System.out.println(“Hi”);
}
}
ThreadLocal
class SomeClass { static ThreadLocal myObject;
}
Finalizer
class SomeClass { public void finalize() {
…
}
}
& vs &&
result = first() & second();
result = first() && second();
result = first() | second();
result = first() || second();
result = first() ^ second();
Static Class Inside an Interface
interface SomeInterface { …
static class SomeClass {
static void staticMethod() {
…
}
}
}
Strings & Encodings
Strings vs Bytes
• String – tähtede jada• Stringi saab kodeerida baitide jadaks.• See kuidas see kodeerimine toimub nimetatakse
“encoding”.• Encodingud on erinevad (ASCII, ISO-Latin, UTF-
8, etc)• Failides salvestatakse ja võrgus saadetakse baite,
programmis töötatakse tähtedega. Tuleb jälgida et konversioonid oleksid kõikjal õiged.
Streams
• Javas on 2 tüüpi voogusid: – InputStream/OutputStream: kirjutavad-loevad
baite– Reader/Writer: kirjutavad-loevad tähti.
• Streamist saab teha Writer-i:– new OutputStreamWriter(new FileOutputStream());
• Writeri-sse saab kirjutada baite:– writer.write(new String(byteArray));
Streams
• Mõlemad näited eelmisel slaidil on valed.
• Peab olema:– new OutputStreamWriter(
new FileOutputStream(),
“UTF-8”);
– writer.write(
new String(byteArray, “UTF-8”)
);
Last Slide: Concatenating Strings
String s = “”;
for (int i = 0; i < a.length; i++) {
s = s + a[I];
}
StringBuffer s = new StringBuffer();
for (int i = 0; i < a.length; i++) {
s = s.append(a[I]);
}
Bad:
Good:
Küsimused?