Java程序执行流程(JVM)

  • Post author:
  • Post category:java


首先了解JVM架构:

CSDN

硬件决定执行性能:JDK1.8之前(1.8之后 JVN可以不完全受到硬件的性能制约)

类加载器ClassLoader 三层:

  • BootStrap 系统类加载器,涉及JVM的本地实现,获取不到,加载JDK里的API,如java.* ,java.lang
  • ExtClassLoader 扩展类加载器(D:\java\jdk1.8.0_251\jre\lib\ext目录下的 / 平台类加载器
  • AppClassLoader 自定义类加载器
public class Test{
    public static void main(String[] args){    
        //String 是一个系统类,系统类的类加载器是不一样的Bootstrop
        String str = "hello";//静态常量池进行定义,因为字符串这个类型是我们开发中用的非常多的一个数据类型
        System.out.println(str.getClass().getClassLoader());//null

        Member member = new Member();
        //AppClassLoader 自定义类加载器
        System.out.println(member.getClass().getClassLoader());
        //ExtClassLoader扩展类加载器 jdk/jre/lib/ext/...
        System.out.println(member.getClass().getClassLoader().getParent());
        //BootStrap 系统加载器无法获取,由JDK实现
        System.out.println(member.getClass().getClassLoader().getParent().getParent());//null
    }
}

class Memeber{}

编译:

从上往下执行,先从系统类库(JDK)中查找这个类,再往下一致查找classpath,若没有,则会抛出编译异常

执行:

自低向上查找,先从classpath中查找,若没有,则继续从父加载器中查找,直到Bootstrap,若找不到,则会抛出ClassNotFoundException异常

双亲委派机制(自低向上查找时出现): 系统类由系统类加载器负责,而自定义类由其它的类加载器负责

双亲委派机制作用:

1)防止类的重复加载(如果calsspath中找到就不会在往上查找)

2)安全(防篡改字节信息)


不同的类加载器加载的类的信息,在内存中是不一样的,比如:系统自带String和自己写的String类加载在内存中的内容是不一样的。


类加载的字节码文件会加载到运行时数据区里。

运行时数据区内部结构:

CSDN

执行引擎负责执行运行时数据区加载的函数,JNI接口包括本地函数库的调用。Java没有C、C++运行快的原因:Java面向虚拟机的指令编程,而不是面向软件的应用编程。


JVM调优:


1,尽量减少GC的操作;


2,参数调优

运行时数据区(内存问题)?

深颜色的是方法区和堆是线程共享区,浅色的栈内存、程序计数器和本地方法栈是线程私有区。

1)方法区:最重要的一个内存区域,多线程共享,保存了类的信息(类名、成员、接口、父类),反射机制是重要的组成部分,动态的进行类操作的实现

2)堆内存(Heap):解决的是数据存储的问题,保存对象的真实信息,该内存牵扯到释放问题(GC):

CSDN


3)栈内存(Stack):解决程序的运行问题,即程序如何执行,或者说如何处理数据。线程的私有空间,在每一次进行方法调用的时侯都会存在栈帧,采用先进后出的设计原则。

栈帧:

  • 本地变量表:局部参数或者形参,允许保存32位的插槽(Solt),如果超过32位的长度就需要开辟两个连续性的插槽(long,double)–volatile关键字问题

  • 操作数栈:执行所有的方法计算操作

  • 常量池引用:String类实例等

  • 返回地址:方法执行完毕后的恢复执行的点


4)程序计数器:执行指令的一个顺序编码,该区域的所占比率几乎可以忽略

5)本地方法栈:与栈内存功能相似,区别在于是为本地方法(JNI)服务的

举例:

User user = new User();
  • User 类信息会存在方法区中
  • User的实例user,存储在Java堆内存中
  • 使用的都是User对象的引用(指针)
public static void fun(){
    fun();
}

注意:没有退出条件,会抛出异常 :StackOverError ,每调用一次方法就会在栈里产生一个栈帧,当栈帧满了就会抛出此异常



版权声明:本文为weixin_40959890原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。