jvm

JVM即Java Virtual Machine,java虚拟机。在java程序员日常的编程中不太会接触到这种层面的东西,但是如果你了解了这些,你才能对java的运行机制有个了解,可以编写更加低层的代码,可以排查更加诡异的问题。只有理论知识达到了,遇到问题才可以有武器去解决它。

我们主要应该要了解jvm加载class的过程,如何管理并分配内存,执行垃圾收集等功能。

我们先来聊聊jvm加载class的过程。

类加载

jvm使用类加载器来加载class。而类加载器又有以下几种类型:

1.Bootstrap classLoader:主要负责加载核心的类库(java.lang.*等)。

2.ExtClassLoader:主要负责加载jre/lib/ext目录下的一些扩展的jar。

3.AppClassLoader:主要负责加载应用程序的主函数类。

4.CustomClassLoader:自定义类加载器,比如tomcat的StandardClassLoader就属于这类加载器。

那么如果加载一个自定义的Car类,那么按照定义就是由AppClassLoader来加载的。如果自己自定义了一个java.lang.String类呢。是由什么来加载的呢。是AppClassLoader吗?并不是。这就涉及到jvm的双亲委派机制了。他的运行机制大概是这样的:一个类加载器来加一个类的时候,并不会首先让自己去加载这个类,而是委托给自己的父类加载器来加载这个类,自己的父类又委托给他的父类,直到Bootstrap来加载,如果没发加载,再一层一层委派下去,直到自己。

所以自己定义的一个java.lang.String,首先AppClassLoader会委派给ExtClassLoader去加载,ExtClassLoader又委派给Bootstrap classLoader去加载。

这种机制很好的杜绝了某些程序恶意的修改了java的核心类,造成严重的影响。

我们来看一下ClassLoader的loadClass方法

![图片.png](https://upload-images.jianshu.io/upload_images/18159984-854fd238054827aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

可以看到如果存在父类加载器的话,就首先使用父类加载器来加载这个类。

但是双亲委派机制也可以被破坏,比如现在的各种代码热部署技术,如阿里的jarsLink。在这里不详细赘述。

内存模型及垃圾回收

JVM内存结构分为:

1.方法区(method):存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息

2.栈内存(stack):存放一些基本类型的变量数据和对象的引用变量,每个线程都有自己的栈空间。

3.堆内存(heap):堆内存用来存放由new创建的对象和数组,所有线程共享,有java虚拟机的垃圾回收器进行管理

4.本地方法栈(java中的jni调用)。

垃圾回收回收的是堆内存的空间,堆内存又分为年轻代,年老代,元空间。年轻代又分为E区跟S0,S1区,使用的垃圾回收算法是标记清除算法,以求获得连续的内存空间,年老代使用的是标记清理算法。

新建的对象放到年轻代的E区,如果是大对象直接进入年老代。当E区满了的时候,触发一下YoungGC,将E区跟S0区存活的对象,放到S1区,然后将E区S0区全部清空,接受新的对象。经历过多次YoungGC依旧存活的对象,会放到老年代中。逐渐老年代也满了的话,就触发一次full GC。

那么什么对象是被认为存活的呢。jvm目前采用的是可达性分析算法。从gcroot开始找。只要可达就认为存活,那么什么样的对象可以当作gcroot呢

1.java虚拟机栈(栈帧中的本地变量表)中的引用的对象。

 2.方法区中的类静态属性引用的对象。

3.方法区中的常量引用的对象。

 4.本地方法栈中JNI本地方法的引用对象

你可能感兴趣的:(jvm)