JVM是Java Virtual Machine(Java虚拟机)的缩写,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 简单来说,所有的Java程序都是在JVM中运行的。
Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。 Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。
作用:加载class文件
类型:
了解完类加载器的类型之后,就能明白双亲委派机制的原理了。这里只是简单介绍一下,如果想
深入了解,可以点击这里
双亲委派机制的作用原理
如果你写了这样一行代码
new Thread().start();
,然后去查看源码,会发现这样一行代码private native void start0();
。是不是感觉很奇怪。
我们知道java的底层是用C/C++写的。
如果一个方法带了native关键字,说明Java作用不到这个方法,它就会调用底层C语言的库。
在加载class文件时,这个方法会进入本地栈(native method Stack),调用本地方法接口(JNI),来加载本地方法库。
本地方法接口(JNI)的作用:扩展java的使用,融合不同的语言为Java使用。
1. 什么是方法区(Method Area)?
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。
2.方法区(Method Area)存储什么?
它存储已被Java虚拟机加载的类信息、常量(final修饰)、静态变量(static)、即时编译器编译后的代码等
在jdk7及以前,习惯上把方法区称为永久代,jdk8开始,使用元空间取代了永久代。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代最大的区别在于:元空间不再虚拟机设置的内存中,而是使用本地内存
栈(Stack):线程私有的内存区域。一个线程对应一个栈。线程一旦结束,栈就Over。
栈存储的是什么?
八大基本数据类型, 堆中对象的引用。
被所有线程共享的一块内存区域,在虚拟机启动时创建。Java堆(Java Heap)唯一目的就是存放对象实例。所有的对象实例及数组都要在Java堆(Java Heap)上分配内存空间。
关于堆的详细介绍,请点击这里
代码实例
public class PersonTest {
//a存放在栈中 a如果赋值,也存放在栈中
public int a;
//存放在方法区
public static String name="dz";
public static void main(String[] args) {
//PersonTest 存放在方法区 test存放在栈 new PersonTest()实例化对象存放在堆中
PersonTest test = new PersonTest();
//存放在堆中
test.a=1;
System.out.println(test.a);
//堆中没有name的值,则去栈获方法区中找
System.out.println(test.name);
}
}
GC主要在方法区和堆中进行
接下来介绍几个GC常用的算法。
如图所示,每个对象创建的时候都会有一个计数器跟随,对象引用一次,计数器加1。进行GC时,如果计数器显示为0,则被清除。可以看出这种算法非常低效,因此JVM不使用这种算法。
前边为了理解方便,使用了幸存者0区,幸存者1区。实际上叫from区和to区。只是名称不同而已。
幸存者from区和幸存者to区不是固定不变的,而是相互转换。记住一句话,谁空谁是to。
原理
复制算法的最佳使用场景:对象存活度较低的时候,即新生区。
好处:没有内存碎片
坏处:浪费了内存空间
这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如图3-1所示,对象object 5、object 6、_object 7虽然互相有关联,但是它们到GCRoots是不可达的,所以它们将会被判定为是可回收的对象。
在Java语言中,可作为GC Roots的对象包括下面几种:
原理
通过可达性分析算法,将需要清除的对象进行标记。在标记完成后统一回收被标记的对象。
它是最基础的算法,后边的算法都是基于此进行改进的。
缺点
一个是效率问题,标记和清除两个过程的效率都不高
另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
标记压缩算法主要是为了解决标记清除算法的空间问题。 即清除过后将对象都移到一边,这样就不会有内存碎片。但是时间复杂度又变高了,因为需要对内存再扫描一次。
没有最好的算法,只有最合适的算法。 GC采用的是分代收集算法。 即在不同的代使用不同的算法。
年轻代由于存活率低,所以使用复制算法。
老年代(养老区)由于区域大,存活率高,使用标记清除+标记压缩混合实现。 即进行几次标记清除后,有足够多的内存碎片,在进行一次标记压缩。
这里只是简单地介绍一下JVM的相关知识,还有很多没有涉及到。如果想了解的更详细一点。建议看《深入理解Java虚拟机》这本书。想要电子版资源的,请点击链接
提取码:y5yu