JVM学习笔记

 

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

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值