一、 jvm运行机制

本文详细介绍了JVM的启动流程,包括如何找到执行文件和初始化JNIEny接口。接着,分析了JVM的执行基本结构,如栈、堆、方法区的交互,强调了操作数栈在参数传递中的作用。此外,讨论了栈内存的优化,通过代码实例展示了逃逸分析对性能的影响。最后,阐述了JVM的内存模型,强调了volatile关键字在多线程中的作用以及JVM的两种运行方式:解释运行和编译运行(JIT)。
摘要由CSDN通过智能技术生成

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)

–      将字节码编译成机器码

–      直接执行机器码

–      运行时编译

–      编译后性能有数量级的提升

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值