JVM学习理解

JVM学习理解

1.JDK Java 开发工具包。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。

2.JRE(java运行时环境)包含JVM的java程序的运行环境 。

3.JVM是Java程序运行的容器,但是他同时也是操作系统的一个进程,因此他也有他自己的运行的生命周期,也有自己的代码和数据空间。

JVM运行原理

JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种基于下层的操作系统和硬件平台并利用软件方法来实现的抽象的计算机,可以在上面执行java的字节码程序。

java编译器只需面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译器,编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。
JVM学习理解
JVM在整个jdk中处于最底层,负责与操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也叫虚拟计算机.操作系统装入JVM是通过jdk中Java.exe来完成,通过下面4步来完成JVM环境。
1).创建JVM装载环境和配置
2).装载JVM.dll
3).初始化JVM.dll并挂接到JNIENV(JNI调用接口)实例
4).调用JNIEnv实例装载并处理class类

JVM执行程序的过程 :
I.加载.class文件
II.管理并分配内存
III.执行垃圾收集

JVM组成

1.类加载子系统(classLoader)
2.方法区
3.java堆
4.直接内存
5.垃圾回收系统
6.java栈(保存着栈帧信息,栈中存储局部变量,方法参数返回地址)
7.本地方法栈(本地方法)
8.PC寄存器
9.执行引擎(最核心的组件,JIT即使编译)

JVM学习理解
JVM学习理解

1)类加载子系统负责从文件系统或者网络中加载Class信息。

2)java堆在虚拟机启动的时候建立,它是java程序最主要的内存工作区域。几乎所有的java对象实例都存放在java堆中。(线程共享

3)java的NIO库允许java程序使用直接内存。直接内存是在java堆外的、直接向系统申请的内存空间。通常访问直接内存的速度会优于java堆。因此出于性能的考虑,读写频繁的场合可能会考虑使用直接内存。由于直接内存在java堆外,因此它的大小不会直接受限于Xmx指定的最大堆大小,但是系统内存是有限的,java堆和直接内存的总和依然受限于操作系统能给出的最大内存。

4)垃圾回收系统是java虚拟机的重要组成部分,垃圾回收器可以对方法区、java堆和直接内存进行回收。java中所有的对象空间释放都是隐式的,没有类似free()或者delete()这样的函数释放指定的内存区域。

5)java虚拟机栈(java virtual machine stacks),描述的是java方法执行的内存模型。一个线程的java栈在线程创建的时候被创建,java栈中保存着帧信息,java栈中保存着局部变量、方法参数,同时和java方法的调用、返回密切相关。线程私有

6)本地方法栈和java栈非常类似,最大的不同在于java栈用于方法的调用,而本地方法栈则用于本地方法的调用,作为对java虚拟机的重要扩展,java虚拟机允许java直接调用本地方法(通常使用C编写)

7)PC(Program Counter)寄存器也是每一个线程私有的空间,java虚拟机会为每一个java线程创建PC寄存器。在任意时刻,一个java线程总是在执行一个方法,这个正在被执行的方法称为当前方法。如果当前方法不是本地方法,PC寄存器就会指向当前正在被执行的指令的地址。如果当前方法是本地方法,那么PC寄存器的值就是undefined线程私有

8)执行引擎是java虚拟机的最核心组件之一,它负责执行虚拟机的字节码,现代虚拟机为了提高执行效率,会使用即时编译技术将方法编译成机器码后再执行。

9)方法区中可能会存放虚拟机加载的类信息、运行时常量池信息,常量、静态变量、即时编译器编译后的代码数据(这部分常量信息是Class文件中常量池部分的内存映射(线程共享)。

java堆

java堆分为新生代和老年代。其中新生代存放新生对象或者年龄不大的对象,老年代则存放老年对象。新生代有可能分为eden区、s0区、s1区,s0区和s1区也被称为from和to区,他们是两块大小相同、可以互换角色的内存空间
JVM学习理解
在绝大多数情况下,对象首先分配在eden区,在一次新生代回收之后,如果对象还存活,则进入s0或者s1,每经过一次新生代回收,对象如果存活,它的年龄就会加1。当对象的年龄达到一定条件后,就会被认为是老年对象,从而进入老年代。

package com.jvm;
public class SimpleHeap {
	private int id;
	public SimpleHeap(int id){
		this.id = id;
		}
		public void show(){
		System.out.println("My id is "+id);
		}
	public static void main(String[] args) {
		SimpleHeap s1 = new SimpleHeap(1);
		SimpleHeap s2 = new SimpleHeap(2); 
		s1.show();
		s2.show();
	}
}

JVM学习理解

java栈

java栈是一块线程私有的内存空间。与线程执行密切相关。线程执行的基本行为是函数调用,每次函数调用的数据都是通过java栈传递的。

java栈是一块先进后出的数据结构,只支持出栈和进栈两种操作,*在java栈中保存的主要内容为栈帧(==每一次函数调用,都会有一个对应的栈帧被压入java栈,每一个函数调用结束,都会有一个栈帧被弹出java栈。==如下图:栈帧和函数调用。函数1对应栈帧1,函数2对应栈帧2,依次类推。函数1中调用函数2,函数2中调用函数3,函数3调用函数4.当函数1被调用时,栈帧1入栈,当函数2调用时,栈帧2入栈,当函数3被调用时,栈帧3入栈,当函数4被调用时,栈帧4入栈。当前正在执行的函数所对应的帧就是当前帧(位于栈顶),它保存着当前函数的局部变量、中间计算结果等数据。

当函数返回时,栈帧从java栈中被弹出,java方法区有两种返回函数的方式,一种是正常的函数返回,使用return指令,另一种是抛出异常。不管使用哪种方式,都会导致栈帧被弹出。

一个栈帧中,至少包含局部变量表、操作数栈和帧数据区几个部分
JVM学习理解
局部变量表存放(Boolean 、byte 、char 、short、int、float、long、double、对象引用 等)

Stack Space(栈) -Xss128K 设置每个线程的堆栈大小

	package com.jvm;
	public class TestStackDeep {
	 private static int count =0;
	 //代码没有出口,造成栈溢出
	 public static void recursion(){
	 	count ++;
	 	recursion();
	 	 }
	 public static void main(String[] args) {
	 try{
		 recursion();
		 }catch(Throwable e){
	  		System.out.println("deep of calling ="+count);
	 	 e.printStackTrace();
	  }
	}
}

JVM学习理解 **栈帧组成之局

由于局部变量表在栈帧之中,因此,如果函数的参数和局部变量很多,会使得局部变量表膨胀,从而每一次函数调用就会占用更多的栈空间,最终导致函数的嵌套调用次数减少。