《分布式java应用:基础与实践》笔记3

《分布式java应用:基础与实践》笔记3

3.1 java代码执行机制


3.1.1源码编译机制


3.1.2 类加载机制


装载:将字节码装载至JVM。识别类:类的全限定名+ClassLoader实例ID(对于接口与非数组型类;对于数组类,数组的元素类型由ClassLoader加载,数组类由jvm创建)

链接:字节码格式(二进制)校验,(JVM规范)---->初始化类中静态变量——>验证方法权

限。

初始化:静态初始化代码、构造器、静态属性等等

JVM的类加载通过ClassLoader及其子类完成


Bootscrap Class Loader : C++实现此类,所以代码无法拿到该对象。不属于ClassLoader子类。

Extension Class Loader : 对应类名为ExtClassLoader。拓展功能jar包

System Class Loader :对应类名为AppClassLoader。Classpath目录中的jar包。

JVM保证一个ClassLoader实例只加载一次同名的类,从而实现类的隔离。

3.1.3 类执行机制

         字节码解释执行

         Invokestatic、invockevirtual、invokeinterface、invokespecial四个指令执行不同方法调用。


线程在创建后,都会产生程序计数器PC,PC存放下一条要执行的指令在方法内的偏移量;栈中存放了栈帧,每个方法每次调用都会产生栈帧。栈帧主要分局部变量区和操作数栈两部分,前者存放局部变量和参数,后者产生中间结果。栈帧中还会一些杂用空间。

1)  指令解释执行

2)  编译执行:为提高效率,将频率高的代码编译执行。

Client compiler优化方法:方法内联(调用到的方法直接植入当前方法中)、去虚拟化(如果类的方法只有一个实现类,使用方法内联)冗余消除,根据运行状况时行代码折叠或削除。

Server compiler优化方法:标题替换(用标题替换聚合量,如X替换point.x);栈上分配(如果对象没逃逸,C2选择在栈上直接创建对像实例)同步削除(如果同步的对象未逃逸,则没有同步的必要。)

3)  Sun JDK未选择在启动时即编译成机器码的原因:

a)        静态编译不能根据程序运行状况优化执行代码。

b)        解释执行比编译执行更节省内存。

c)        启动时解释执行的启动速度比编译再启动更快。

但程序在未编译期间解释执行方式会比较慢,因此需要一个权衡值。

反射执行

         可动态调用某对象实例中对应的方法、访问查看对象的属性,无需在编写代码时就确定要创建的对象。(getMethod比较耗性能,一要权限校验,二要所有方法扫描及Method对象复制)

3.2  JVM内存管理

3.2.1 内存空间


方法区:存放要加载的类的信息、静态变量、final类型常量、类Field信息、类的方法信息。通过-XX:PermSize及-XX:MaxPermSize来控制。

堆:存储对象实例及数组值.-Xms和-Xmx控制。为避免在运行时频繁调整Heap大小值设一样。

Jdk1.2开始分代管理内存。


新生代(New Gerneration):新建对象,-Xmn来指定

旧生代(Old Gerneratiion): 缓存对象。-Xmx 减去- Xmn决定。

-XX:PretenureSizeThreshold=1024(字节)表示当对象超过多大时就尖就不在新生代分配,直接在旧生代分配。

本地方法栈:用于支持native方法的执行。存储每个native方法调用的状态。在SunJDK实现中本地方法栈和JVM方法栈是同一个。

PC寄存器和JVM方法栈:每个线程均会创建PC寄存器和JVM方法栈。前者占用可能为CPU寄存器或操作系统内存。JVM方法栈占用的为操作系统内存。JVM方法栈为线程私有,分配内存上非常高效。当方法运行完毕对应栈帧所占用内存也会自动释放。JVM方法桡空间不足会抛出StackOverflowError.。在JDK中可通过-Xss来指定其大小。

3.2.2 内存分配

         Java对象在堆中分配,堆为线程共享,因此在堆中分配内存要加锁。堆空间不足触发GC。GC后不足,触发OutofMemery。

         TLAB(Thread localAllocation buffer):用于提升内存效率。在每个新创建线程的新生代的EdenSpace提供独立区域。大小由JVM根据运行情况计算而得。可通过-XX:TLABWasteTargetPercent来设置TLAB可占用Eden Space的百分比。默认1%。影响TLAB空间大小参数:-XX的配置、线程数量、线程是否频繁分配对象。TLAB上分配内存不需要加锁,因此JVM尽量在TLAB上分配对象内存。可通过在启动参数上增加-XX:+PrintTLAB来查看空间使用情况。

除了在堆上分配及TLAB上分配还有基于逃逸分析直接在栈上进行分配的方式。

3.2.3 内存回收

         通常采用收集器的方式实现GC,有可引用计数收集器和跟踪收集器。

         可用计数收集器:在循环引用中无法GC

         跟踪收集器:采用集中管理,全局跟踪对象引用状态。通过事件触发从根集合扫描引用关系。

         根据不同的区域采用不同的GC:


         MinsorGC 、Full GC等略。

3.2.4 内存查看方法与分析工具

         1,输出日志:需要人为分析。

         2,GC Portal:帮助分析GC日志。需要老版本Tomcat

         3,,Jconsole:JDK5以上自带工具。

         4,JvisulVM:JDK6 update7之后的工具。可安装VisualGC插件来分析GC趋势。

         5,JMAP:JDK 的bin目录下。分析JVM内存状况

         6,JHAT:6以后自带(bin下),分析JVM堆dump工具。

         7,JSTAT:除以上,还可看编译状况。

         8,EclipseMemory Analyzer:eclipse提供的工具。

3.3 内存线程资源同步与交互机制

3.3.1 资源同步机制

         Lock/unlock。Sychronicze从略

3.3.2 交互机制

         Wait/notify方法。从略

3.3.3 线程状态与分析


(略)

猜你喜欢

转载自blog.csdn.net/lylhjh/article/details/51540068