java reflection is to get and modify existing class, method, field behavior, like access modifier.
To note, this is an expensive operation.
Serializable is a marker interface. ObjectOutputStream’s writeObject method is for serialization and ObjectInputStream’s readObject is for deserialization. These methods could be override to provide customized serialization.
Transient variable will be ignored during serialization.
3. dynamic proxy
this follows the proxy pattern, kind of adding a proxy/facade before the read method invocation.
default clone method (native method in Object) is shallow copy; which is primitive types are cloned with value; objects are
“cloned with value (memory address)”
to do deep clone, serialization is one approach. another approach is to override the clone method for object variables.
stack is for methods runs, each method corresponding to one stack frame added ontop of each other, and removed once the method finish;
local primitive methods during the method invocation are stored on stack, and cleared once method finish; while object created/referred in methods are put onto heap
Stack can be set up during JVM start up using -Xss (maximum for stack memory)
one example for possible stack overflow is, for recursive function calls, if it went too deep, it could cause stackOverFlow
heap is the main memory portion within JVM, can be divided into two parts Yong Generation (Eden + S1 + S2/Survivor) and Old Generation/Tenured space
Before Java 8, it’s using PermGen to store class info, metadata, and string pools. After java 8, permGen is removed, and something equivalent is created called MetaData space
recent JVM implementation are using generational GC. which is minor GC on young generation (where there is not enough eden space to put new objects); major GC on tenured space (when there is not enough memory on Tenured space to put objects)
There are multiple GC algorithms, like serial, paralel, ParNew, CMS, G1 etc. for young generation, most recent JVM (hotspot, IBM, JRocket) are using copying algo for GC on young generation, because more of the objects are actually not long lasting. So after objects created and put onto Eden, the first Young GC could have most of the objects cleared. while remaining (minority) survived would be COPIED to S1/To Survival space. At any time, there is always one S1/S2 survival space empty to be copied to.
by default after 15 cycles (this can be changed by setting up the survival ratio as JVM parameter), (if the object has been surviving after 15 coping GC), it will then be promoted to tenured space.
There are exceptions, if the object is too big to put onto eden of Survival space (eden to S1 to S2 is 8:1:1), it could promoted to Tenured space immediately.
for GC on tenured space, before Java 8, for recent JVM, it’s using CMS. (which is good for concurrency, and first mark the object to be cleared, which then invokes the finalize method, for last try, if the object still not referenced (used to be using reference count, now new JVM using GC roots reach-ability), then the object would be swept.)
note: JVM stack is for the stack for Java methods/stack; while native stack is for native (non-java) methods.
6. class loading
in Java, it’s delegating Parent class loader to load the class. so unless the class cannot be loaded from bootStrap (JRM/lib), Extension (JVM/lib/ext), System class loader, and the parent class loader(could be EAR, then WAR, then JAR), then child class loader.
this implementation would avoid the classCast exception, where different copies of same class loaded by different class loader, which is incompatible with each other.
7. memory leak
There are two types of memory leak. if objects are created, and later no longer used, however cannot be GCed, these objects would continue to hog the memory. examples are, the objects are referred by static variables of some long lived classes (class are normally live in permGen/Meta space, and would live till JVM exits); or the objects are referred by collections (the object might no longer used, however, the collection still hold a pointer to the object); inappropriate implementation of the object, for example equals & hashCode. it could happens the object could be put on a hash bin/node/bucket, however, never able to be retrieved, as the equals method doesn’t comply with hashCode implementaion.
another type of memory leakage, is object creation faster than GC. there are some framewoks/library/or wrong implementations, generating objects (per thread, per request, as proxy, as prototype) very fast, which GC is not able to catch up, could cause OOM.
8. happens before
JVM could re-arranged order of code executions for better performance (JIT compiler optimization, for example grouping operations on same object together). however, for certain operations, the happens before must satisfy no matter how the code re-arranged.
happens before, means the previous operation visible to following operation.
volatile: write operation must happens before for the read operation. since volatile variables are directly operating on the main memory, so write of the variable would be visible for all subsequent reads.
lock: unlock happens before unlock. only once the lock released (marker work removed the thread info), subsequent calls can then acquire the lock (put the new thread’s info onto the marker word).
Transitivity: if A happens before B, B happens before C, then A happens before C.
Thread start rule: the start method happens before every actions on the spawned thread.
9. permgen vs metaspace
Before Java 8, it’s using PermGen (Permaneent Generation, the JVM Generational) to store those class, meta data info. PermGen was part of the JVM. so if too many classes initiated for example, it could cause the permGen space generate OOM. (String pools were also put into permGen before for some old HotSpot JVM, before Java 7.)
from Java 8, permGen has been removed, and it has allocate a new space called MateSpace (kind of like renaming) for storing same information. However, metaSpace now lives on the native memory, which literately wont throw OOM. (unless whole native memory for the JVM process used up, in which case OOM wont be thrown either as the JVM is killed.)
JVM Default maximum PermGen size (MB) Default maximum Metaspace size
32-bit client JVM 64 unlimited
32-bit server JVM 64 unlimited
64-bit JVM 82 unlimited
permGen size could be adjusted same as other vm paramters, (like oss, xms, xmx. etc )-XX:PermSize=N, or -XX:MaxPermSize=N.
note, if the permGen is set to small initially, it could require multiple increases (before reaching maxPermSize). each resizing would cause a FULL GC.
This could happens during JVM start up, as it realizes more permGen (or xms, heap space) needed, it would busy resizing, which take/waste a lot time.
so one important JVM tuning is to set up a proper permSize (same as xms), so that resizing, and full GC (expensive operations) could be minimized.
same as permGene,
-XX:MetaspaceSize –the initial of the Metaspace
-XX:MaxMetaspaceSize –the maximum size of the Metaspace
10. Java Memory Model (JMM)
11. garbage collection (GC)
right now, most JVM (HotSpot, JRocket, etc) are using generational JVM memory modeling and GC.
This is the default space allocation on heap.
if not enough space on new space (object too big to put onto eden), it could trigger minor GC. because most of the object are short lived, so minor GC is using copy algorithm, basically remove most objects (since most are short lived), and copy surviving objects into one of the survivor space (from/to , or s1/s2). default survival ration is 15. once the object has passed 15 minior gc and survived, it will be promoted to tenured space (like tenured). another case for promotion, is if the object is too big (even larger than S1/S2 space for example, so no way for them to stay on new space). (“too big too fail/to kill early”)
on Tenure space, before java 8/9 (using G1), CMS is most popular. basically it’s concurrent version of sweep. if an object (GC roots not reachable), it would be marked (run the finalize method), still not reachable, then swept.
12. program registers
PC (program counter register) is thread bound (live per thread), used for register current execution code line number, and direct for next running line (number).
if it’s running java method, registered is the line number of the byte code.
if it’s running native method, register is undefined.