JVM体系结构:
1。类加载器子系统
2。执行引擎
3。数据区(内存结构)
JVM执行引擎:
基于栈的指令集:一个指令(操作码、操作数)
执行技术:解析执行、编译执行(JIT)
线程:
主内存: VM共享
工作内存(TLAB--Thread Local Allocation Buffer):线程自己的
数据区主要包括以下四个:
方法区: 解析出来的类型信息.....
堆区: 创建的对象......
PC寄存器 和 Java方法栈: 线程信息、栈帧(局部变量区、操作数栈)
本地方法栈:为本地方法库所设计(Sun JDK的实现中与Java方法栈是同一个)
一、Java源码编译机制:
1。分析和输入到符号表(Parser And Enter):
词法分析 com.sun.tools.javac.parser.Scanner:将代码字符串转变为token序列。
语法分析 com.sun.tools.javac.parser.Parser:Token序列生成抽象语法树。
输入到符号表 com.sun.tools.javac.comp.Enter: 类中出现的符号输入类自身的符号表中等。
2。注释处理(Annotation Processing)
用于处理用户自定义的annotation,
处理后再次进入Parser And Enter步骤。
3。语法分析和生成class文件(Analyse and Generate)
基于抽象语法树进行一序列语义分析,
再完成分析后, 开始生成class文件 com.sun.tools.javac.jvm.Gen 。
二、类加载机制(类加载器子系统的工作职责与工作流程):
1。装载(Load): 查找并装载二进制字节码, 采用两个元素来标识一个被加载的类:类的全限定名+ClassLoader实例ID。
2。链接(Link): 校验(Verify)--格式校验确保被导入类的正确性-->准备(Prepared)--为类变量分配内存空间并初始化默认值-->解析(Resolve)--把导入类的符号引用转换为直接引用。
3。初始化(Initialize):执行类中的静态初始化代码、构造器代码及静态属性的初始化。
Class Loader双亲委派模型:
Bootstrap Class Loader--$JAVA_HOME/jre/lib/rt.jar ( 曾祖父)<--
Extension Class Loader--$JAVA_HOME/jre/lib/ext/*.jar (祖父)<--
System Class Loader--$CLASSPATH(父亲)<--
User-Defined Class Loader
三、类执行机制:Sun JDK 基于栈的体系结构来执行字节码,代码紧凑,体积小。调用方法 invokestatic、invokespecial、invokevirtual、invokeinterface。
1。字节码解释执行
指令解释执行:对于方法的指令解释执行,执行方式为经典冯*诺依曼体系的FDX循环方式,有switching-threading、token-threading、direct-threading、subroutine-threading、inline-threading。
Sun JDK主要的优化:
栈顶缓存(top-of-stack caching):即将本来位于操作栈顶的值直接缓存到寄存器上, 这对于大部分只需要一个值的操作而言,无须将数据放入操作数栈, 可直接在寄存器计算, 然后返回操作数栈。
部分栈帧共享:当方法调用时, 后一个方法可将前一方法的操作数作为当前方法的局部变量,从而节省数据copy带来的消耗。
2。字节码编译执行
解释执行的效率较低,为提升代码执行性能, Sun JDK提供将字节码编译为机器码的支持,编译在运行时进行, 通常称为JIT编译器。
Sun JDK在执行过程中, 对执行频率不频繁的代码采用解释执行,执行频率高的代码采用编译执行。
Sun JDK主要的优化:
Client Compiler(C1):
方法内联: -XX:MaxInlineSize=字节数 进行控制。
去虚拟化:进行类的层次的分析,如发现类中的方法只提供一个实现类,那么可以对调用此方法的代码进行方法内联。
多余消除:根据运行状况进行代码折叠或消除。
Server Compiler(C2):
标量替换:用标量替换聚合量,如:用基本类型替换对象。
栈上分配(TLAB):对于未逃逸对象可以直接在栈上分配,而不是JVM堆上。
同步消除:如果发现同步对象未逃逸,可以去掉同步。
Sun JDK之所以未在启动时即编译成机器码, 有几方面原因:
根据运行状况来进行动态编译,为C2收集运行数据的越长的时间,编译出来的代码会比静态编译更优越。
解释执行比编译执行更节省内存。
启动时解释执行的启动速度比编译再启动执行更快。
(小记:当java -server出现Error: no `server' JVM at `XXX/bin/server/jvm.dll'错误时,解决方法可以复制jdk下jre/bin/server目录到jre7/bin目录下;或 windows下可以通过修改注册表HKEY_LOCAL_MACHINE/SOFTWARE/JavaSoft/Java Runtime Environment; UNIX下更改/usr/java的链接)
3。反射执行
基于反射可动态调用某对象实例中对应的方法、访问查看对象的数据等。
最直接的方法是动态生成字节码: Class.forName(Class's Name)。
getMethod相对比较耗性能(装载Class对象、各种(权限等)校验Class、执行构造对象的netInstance、所有方法的扫描及Method对象的复制、......), 反射执行获取的方法与标准的方法调用没有任何区别(method.invoke仅比直接调用低一点), 所以可采用缓存getMethod返回的Method对象来提升性能。
四、JVM内存管理
1。内存空间
方法区(Permanet Generation):全局共享, 在一定条件下它也会被GC, 默认值为16MB, 最大值为64MB(-XX:PermSize和-XX:MaxPermSize)。
存放了要加载的类的信息(名称、修饰符等)、类中静态常量、类中定义为final类型的常量、类中的Field信息、类中的方法信息。
堆(Heap):启动时申请的最小Heap内存(默认值为物理内存的1/64但小于1G)和可申请的最大内存(默认值为物理内存的1/4但小于1G), 通过-Xms和-Xmx来指定。可通过-XX:MaxHeapFreeRatio=指定动态调整的比例。-XX:NewRatio= 参数可以设置Young与Old的大小比例,-server时默认为1:2。
新生代(New Generation--Eden、S0、S1): 可通过-Xmn指定大小,用于存放新对象, -XX:SurvivorRatio来指定Eden Space和Survivor Space分配比例。
旧生代(Old Generation 或 Tenuring Generation): 等于-Xmx减去-Xmn,用于存放新生代经过多次垃圾回收后仍然存活的对像(例如缓存对象)、大对象(新对象直接分配)、大的数组对象(新对象直接分配)。
本地方法栈:用于支持native方法的执行, 存储每个native方法调用状态(Sun JDK的实现中与Java方法栈是同一个)。
PC寄存器 和 Java方法栈:每个线程的创建均会分配, PC寄存器占用的是CPU寄存器或操作系统内存, Java方法栈占用的是操作系统内存。通过-Xss来指定。
2。内存分配
Java对象占用的内存主要在堆上分配, 堆是所有线程共享的,因此在堆上分配内存时需要进行加锁,这导致对象开销比较大。
Sun JDK为了提升内存分配的效率, 会为每个新创建的线程在新生代的Eden Space上分配一块独立的空间, 通过-XX:TLABWasteTargetPercent来设置占用Eden Space的百分比, 默认1%。-XX:+PrintTLAB查看TLAB使用情况。
五、JVM垃圾回收机制
1。引用计数收集器
2。跟踪收集器
复制(Copying)
标记--清除(Mark-Sweep)
标记--清除--压缩(Mark-Sweep-Compact)
增量(Incremental, -Xincgc):火车算法,基本达到非破坏性的渐进式
分代(New Generation--Eden、S0、S1, Tenuring Generation, Permanet Generation)
串行(Serial)
并行(Parallel)
并发(Concurrent)
自适应
3。对象的可触及性与引用性
可触及性: 可触及的、可复活的、不可触及的。
引用性:强引用、软引用、弱引用、虚引用。
4。GC参数
指定日志输出:-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime
指定输出文件:-Xloggc:gc.log
GC跟踪分析:-verbose:gc -XX:+PrintTenuringDistribution -XX:MaxTenuringThreshold=5
GC收集器:-XX:UseSerialGC -XX:+UseParallelGC -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseParallelOldGC -XX:+UseG1GC
其他:-XX:+DisableExplicitGC
学习参考资料:
书:
《分布式Java应用:基础与实践》、《深入Java虚拟机》、《Java语言规范 英文版*第3版》
博客:
Java垃圾回收调优 – Tim[后端技术]: http://timyang.net/java/java_gc_tunning/
关于Java程序的执行的一次分享 - Script Ahead, Code Behind:http://rednaxelafx.javaeye.com/blog/656951