1.jvm整体运行原理: 1)加载:代码需要用到某个类的时候,会触发类加载器,把类从.class字节码文件加载到jvm 2)验证:验证.class文件中的内容是否符合规范 3)准备:a.给需要使用到的类分配内存空间,b.同时给类变量(static修饰变量)分配内存空间,给一个默认的初始值0 4)解析:简单说就是把符号引用替换成直接引用。(过程复杂涉及到jvm底层,暂时放在一边) 5)初始化:执行类的初始化代码。 规则:什么时候初始化一个类? a.主类必须立即初始化, b.实例化使用到的类的对象:此时会触发类加载、验证,然后准备类实例化一个对象,然后解析,初始化。 c.初始化一个类的时候,他的父类还没有初始化,那么必须先初始化他的父类 6)使用 7)卸载
2.类加载器和双亲委派机制: 1)启动类加载器:Bootstrap Classloader,它主要是负责加载我们在机器上安装的java目录下的核心类-“lib”目录中的核心类库。 2)扩展类加载器:Extenxion Classloader,这个加载器也是类似-“lib\ext”目录。 3)应用程序类加载器:Application Classloader,这个类加载器负责加载“Classpath”环境变量所指定的路径中的类。 4)自定义类加载器:根据自己的需求加载类 5)双亲委派机制:jvm的类加载器加载类的时候,由父类先加载,先传达到顶层父类,父类在自己加载范围中找不到,就让子类加载,依次往下传达 顺序:启动类加载器–>扩展类加载器–>应用程序类加载器–>自定义加载器
3.jvm内存区域划分 1)方法区:jdk1.8以前叫做方法区,1.8以后叫"Metaspace",可以理解为"元数据空间"这个意思,主要存放从.class文件加载的类和一些类似常量池的东西。 2)字节码执行引擎:程序计数器:每个线程都有一个程序计数器,专门当前这个线程执行到了哪一条字节码指令。 3)java虚拟机栈:每个线程都有自己的java虚拟机栈,在线程调用任何方法的时候都会给方法创建栈帧然后入栈,在栈帧里面存放了这个方法对应的局部变量之类的元数据,包括这个方法执行的其他信息,方法执行完毕以后就出栈。 4)java堆内存:存放局部变量的对象–栈帧存放方法对应的局部变量,局部变量表只想java堆内存的对象。 内存区域总结: 1.首先,jvm进程启动,加载启动类到内存,然后开启一个main线程执行main()方法,main线程关联一个程序计数器,该程序计数器记录线程执行到哪一行指令。 2.main线程执行mainI()方法的时候,会在main线程关联的java虚拟机栈压入一个main方法的栈帧。接着加载使用到的类到内存并创建该类的对象实例,将该实例分配到java堆内存,并且在main()方法的栈帧里的局部变量表引入一个引用该实例的变量(引用该变量在java堆内存的地址) 3.然后main线程开始执行对象中的方法,会依次把自己执行到的方法对应的栈帧压入自己的java虚拟机线程。执行完方法后再把对应的栈帧从java虚拟机栈帧里出栈
4.垃圾回收原理: 在执行一个方法完毕以后,该方法对应实例栈帧就会从对应的main()线程出栈,一旦该方法对应的实例出栈,在栈帧里面就没有局部变量指向该对应的类的实例,那么垃圾回收线程就会把这个没有栈帧指向的实例对象回收掉,从内存里面清楚掉,让它不再占用内存资源。
以上是今天jvm的学习笔记,如果有不准确或者错误的地方,希望看到的大佬能够指正一下。感谢!
|