1、JVM的启动流程
一个JAVA类运行,装载配置会根据当前路径找JVM.CFG。在配置文件中找到执行文件jvm.dll。然后初始化jvm获得JNIEny接口,该接口会找相应的类运行main方法。
2、执行基本结构
l PC寄存器在线程创建时创建,每个线程都拥有一个寄存器
l 方法区保存装载类的信息(类型的常量池、字段、方法、方法字节码)和Perm永久区关联在一起
l 应用系统对象都保存在java堆中。所有的线程都共享堆内存
l 单独每个线程的私有内存为栈内存,每一次方法调用都创建一个贞,并压栈。通常栈内存非常小,而且及时使用完会被GC回收释放。
Java栈– 操作数栈
Java没有寄存器,所有参数传递使用操作数栈
publicstatic int add(int a,int b){
int c=0;
c=a+b;
returnc;
}
操作执行顺序
0: iconst_0 // 0压栈
1: istore_2 // 弹出int,存放于局部变量2
2: iload_0 // 把局部变量0压栈
3: iload_1 // 局部变量1压栈
4: iadd //弹出2个变量,求和,结果压栈
5: istore_2 //弹出结果,放于局部变量2
6: iload_2 //局部变量2压栈
7: ireturn //返回
java对象是在堆里分配的,在调用栈中,只保存了对象的指针。当对象不再使用后,需要依靠GC来遍历引用树并回收内存,如果对象数量较多,将给GC带来较大压力,也间接影响了应用的性能。减少临时对象在堆内分配的数量,无疑是最有效的优化方法。
代码:
publicclass OnStackTest {
public static void alloc(){
byte[] b=new byte[2];
b[0]=1;
}
public static void main(String[] args) {
long b=System.currentTimeMillis();
for(int i=0;i<100000000;i++){
alloc();
}
long e=System.currentTimeMillis();
System.out.println(e-b);
}
}
添加DoEscapeAnalysis执行
-server-Xmx10m -Xms10m
-XX:+DoEscapeAnalysis-XX:+PrintGC
输出结果 5
去掉DoEscapeAnalysis执行
-server-Xmx10m -Xms10m
-XX:-DoEscapeAnalysis-XX:+PrintGC
[GC 3550K->478K(10240K), 0.0000977 secs]
[GC 3550K->478K(10240K), 0.0001361 secs]
[GC 3550K->478K(10240K), 0.0000963 secs]
564
小对象(一般几十个bytes),在没有逃逸的情况下,可以直接分配在栈上
直接分配在栈上,可以自动回收,减轻GC压力
大对象或者逃逸对象无法栈上分配
2.1栈、堆、方法区交互
public class AppMain
//运行时, jvm 把appmain的信息都放入方法区
{
public static void main(String[] args)
//main 方法本身放入方法区。
{
Sample test1 = new Sample( " 测试1 " );
//test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面
Sample test2 = new Sample( " 测试2 " );
test1.printName();
test2.printName();
}
2.2内存模型
每一个线程有一个工作内存和主存独立,工作内存存放主存中变量的值的拷贝
当数据从主内存复制到工作存储时,必须出现两个动作:
第一, 由主内存执行的读(read)操作;
第二, 第二,由工作内存执行的相应的load操作;当数据从工作内存拷贝到主内存时,也出现两个操作:第一个,由工作内存执行的存储(store)操作;第二,由主内存执行的相应的写(write)操作
每一个操作都是原子的,即执行期间不会被中断
对于普通变量,一个线程中更新的值,不能马上反应在其他变量中
如果需要在其他线程中立即可见,需要使用 volatile 关键字
public class VolatileStopThread extends Thread{
private volatile boolean stop = false;
public void stopMe(){
stop=true;
}
public void run(){
int i=0;
while(!stop){
i++;
}
System.out.println("Stopthread");
}
public static void main(String args[]) throws InterruptedException{
VolatileStopThread t=new VolatileStopThread();
t.start();
Thread.sleep(1000);
t.stopMe();
Thread.sleep(1000);
}
}
volatile 不能代替锁
一般认为volatile 比锁性能好
选择使用volatile的条件是:
语义是否满足应用
3、运行方式
n 解释运行
– 解释执行以解释方式运行字节码
– 解释执行的意思是:读一句执行一句
n 编译运行(JIT)
– 将字节码编译成机器码
– 直接执行机器码
– 运行时编译
– 编译后性能有数量级的提升