前言

  • 作为一名Java软件开发程序猿,不了解JVM?那么你就只能干CRUD的工作!
  • 前几天刚学习了JVM,把学习到的经验在这里和大家分享下,有啥意见,欢迎在下方评论交流!

1.什么是JVM?

JVM全称 Java Virtual Machine(Java虚拟机),是Java模拟出来的一个计算机,运行在操作系统之上。

它的作用是什么呢?

  • 跨平台(移植性高)

   学习过Java的同学应该都知道,Java能够跨平台的重要原因就是得益于JVM,为什么这么说呢?因为我们在编写java代码时,想要运行这个程序,首先得从java文件编译成class(字节码)文件。紧接着由我们的JVM装载这个class文件,然后转化成平台能够识别的指令。整个过程中,JVM扮演了一个翻译官的角色。那么,把打包好的java程序比喻为一位需要去美国旅游的人(名为张三),操作系统比喻成美国,JVM就是张三此次在美国旅游的翻译官。因此,想要在不同的操作系统中运行java程序,只需要更换相应的jvm即可,正如jvm诞生初期所说“一次编译,到处运行”。

所以,我们想要运行Java程序,那么就必须得安装相应的JVM。如果,不需要运行Java程序,只需要开发Java程序,只需要安装相应的JDK。

  • 自动内存管理
    在C语言中,需要自己去分配、释放内存。一个操作不当,就有可能造成程序的死机。下面是一个简单的内存、释放内存代码:
//c语言通过malloc()和free()这两个库函数来实现分配、释放内存空间
// 一方面,对已释放的内存、未曾分配的内存做释放,都会造成死机; 
//另一方面,对不再使用的内存不释放,会浪费系统内存,甚至内存枯竭
#include <stdio.h>
int main(int argc,char* argv[] )
{
	int *p; // 定义一个int类型的指针
	p = (int *)malloc(4); //分配4个连续的内存单元给指针p
	free(p); //释放指针p所指向的内存单元
	printf ("Hello World! \n") ;
	return 0 ;
}



     Java中创建对象时会自动为该对象分配相应的内存空间,当该对象没有被引用地址所引用时,就会被JVM中的GC(垃圾回收器)进行回收。使其在开发时,不需要担心和C语言一样在分配内存和释放内存时所造成的困扰,极大的提高了开发效率。

2.JVM内部原理

上述只是简单的描述了JVM的功能,下面我们仔细的来看看JVM的内部原理。

先看看JVM结构图:

android为什么虚拟机 安卓虚拟机什么原理_jdk

   我们主要看运行时数据区的五大组件:方法区、堆、虚拟机栈、本地方法栈、程序计数器。

方法区:主要保存类的信息如类名、属性、方法、常量池,是线程共享的。

android为什么虚拟机 安卓虚拟机什么原理_java_02

堆:用于存放 java程序在运行时创建的实例对象,也就是开发时 new出来的对象都由堆进行分配内存空间进行存放。堆中没有被引用的对象会由JVM中的GC进行回收(清除),和方法区一样,是线程共享的。

android为什么虚拟机 安卓虚拟机什么原理_android为什么虚拟机_03

虚拟机栈:也可以称之为栈( FILO)即先进后出,用于记录方法的调用路径,负责Java程序的运行,在线程创建时创建。当启动 main方法时,会创建一个主线程,此时就会在栈中创建一个 main方法的栈帧(栈中的每一层都称之为栈帧),如果 main方法中又调用了一个 a方法,那么就会在 main方法的后面为 a方法开辟一个栈帧(入栈)。当 a方法调用完后,则会清除该栈帧(也就是出栈),栈是线程私有的,每一个线程都只有一个栈。

android为什么虚拟机 安卓虚拟机什么原理_jdk_04



如图所示就是报异常打印的栈信息:从下图可以看出,栈中最底层为main方法,当执行到最顶上一层UnixProcess类时报错。

android为什么虚拟机 安卓虚拟机什么原理_编程语言_05


  值得注意的是方法中的变量都存储在方法所在的栈帧里,这也就解释了局部变量只能在当前方法中访问。


本地方法栈:用于执行JVM中 C语言的本地方法,JVM底层是使用 C语言及 C++开发出来的,所以,需要一个Native方法来调用这些C语言中的方法。也就是JNI调用等。

程序计数器:用于线程执行到某个方法时被CPU切换的一个计数器。例如:a线程执行到b方法时如果被CPU切换了,也就是把执行权让给了b线程,那么程序计数器(也可以称为寄存器)就会记录a线程执行到的方法路径。

3.类加载器的分工

android为什么虚拟机 安卓虚拟机什么原理_编程语言_06


引导类加载器:用于加载java中的核心类库,也就是处于jre/lib/rt.jar中的类,Java开头的这些包名。



扩展类加载器:继承于引导类加载器,用于加载jre/lib/ext/目录下的所有jar包。



系统类加载器:用于加载我们自己写的Java类、main方法类。



JAVA它为什么要设计这么多的加载器呢?弄一个加载器加载所有的类它不香吗?

答案就是:提高了整个java程序的安全。假设:有一天有个黑客在你的程序中编写了一个带有病毒的class文件,包名为java.lang.Virus.class。那么大家想想,它能够被加载器成功加载吗?

肯定是不能滴!为什么呢?因为,这些所有的加载器都只会去特定的位置去加载那些jar包或者java类。就算这个病毒类被系统类加载器加载了,它只能破坏到系统类的一些东西。并不能够直接影响到JVM中的数据。

总结

好了,到这里就结束了,技术有限,只能给大家讲解那么多啦!下面简单的总结一下。

 class文件可以说成是我们人类吃的食物,那么类加载器就是我们的嘴巴,只有将class文件被加载器给加载了,才能够进入到JVM中的运行时数据区。也就是我们的肚子。那么执行引擎就是我们的肠胃,对class文件进行消化,转化成平台能够认识的指令。

 虚拟机在执行过程中,会分配相应的内存空间给对象,那么当这些对象无用时,就会清理掉。这时JVM中的GC就会起作用,它会判断哪些对象是无用的。如果是无用的,就会被其回收掉!如果一直不清理,并且一直创建对象,就会造成内存泄漏,直到内存溢出且程序崩溃。就相当于人体内的废物一直得不到排泄,那么总有崩溃的一天。

下篇博客,将会讲解JVM中的GC(垃圾回收机制)的实现原理,有兴趣的小伙伴可以了解下。谢谢大家的阅读!阅后点赞,手留余香!

JVM中的GC实现原理,如何搞挂JVM