JVM基本原理:
-
class文件:
由编译器之间编译成为.class文件, 然后给JVM识别:注意和C语言不同。Class设计想法是平台无关性,class中为JVM规定规范的自定义指令集,符号表等其它一些信息,所以通过JVM屏蔽了机器细节。
-
类加载器:
默认3个加载器:
-
Bootstrap ClassLoader:启动类加载器,最顶层,加载JDK核心类库,resource.jar, charset.jar
不是继承自 java.lang.ClassLoader, 由CPP编写,嵌入到JDK内核中。当Jvm自动启动时会自动执行,加载JDK的核心类库,并构造出另外两个类加载器
-
Extension ClassLoader: 扩展类加载器:加载扩展类库
-
App ClassLoader:负责加载应用程序目录下所有的jar和class文件
-
可以自定义类加载器,需要继承自 java.lang.ClassLoader类,处理Bootstrap外另外两个也是继承自这个。
-
方法区:
用于存储JVM完成加载后的一些信息,和堆区一样线程共享这部门内存区域:
存储比如类型全名,父类型全名,类是接口还是类,修饰符,所有静态变量,一个指向类加载器的引用,一个指向Class类的引用,常量池等。
-
堆区:
创建的类,创建的数组均放在堆区,所有线程会共享这个堆
-
虚拟机栈:
栈中仅仅保存基础数据结构类型,包装类型存在与堆区,不由JVM GC管理的,但是栈内创建的引用类型还是由GC管理的,每一个线程均会有一个栈
-
本地方法栈:
-
程序计数器:
下一条指令执行的位置,每个线程有独立的PC
线程轮流切换并分配处理器来执行
-
执行引擎:
执行引擎可以相当于一个虚拟的物理机器,有自己的定义的指令集,执行引擎的主要职责就是把这些自定的指令集翻译为物理机器的执行集然后执行
-
本地方法接口JNI:可以用本地方法接口去调用原本用其他语言写好的库,但是如果使用会丢失跨平台(因为需要编译本地库),程序由于本地库的调用不当可能奔溃
常量池
-
class文件的常量池:
class文件中的一段内容,存放着字面量,符号引用信息,JVM加载完成后,Class常量池数据会放到运行时常量池中
-
运行时常量池:
方法区的一部分:存放着基本数据数据类型和对象的引用,每一个加载好的Class对象中均有一个运行时常量池。
-
包装类型里实现的常量池及String’常量池:
部门包装类中会自动储存一部分缓存:如果在里面会直接返回池中结果,否则new出一个结果
//IntegerCache.low = -128
//IntegerCache.high = 127
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
//例子
Integer i1 = 200;
Integer i2 = 200;
System.out.println(i1==i2);//返回FALSE
String str1 = "aaa";
String str2 = "aaa";
System.out.println(str1 == str2);//返回TRUE
str1会去里面查找这个对象是否存在,如果存在直接返回引用,否则创建
部分来源于这位大佬的Blog: link