Java基础之JVM

别等时光非礼了梦想. 提交于 2020-01-10 06:00:26

一、内存模型

在这里插入图片描述
1、程序计数器(线程私有)

一块较小的内存空间,是当前线程所指向的字节码的行号指示器。

2、虚拟机栈(线程私有)

是描述java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至完成的过程,对应着一个栈帧在虚拟机中入栈到出栈的过程。
栈帧是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接、方法返回值和异常分派。随方法的创建而创建,随着方法结束而销毁

3、本地方法栈(线程私有)

与虚拟机栈作用类似,区别是虚拟机栈为执行java方法服务,而本地方法栈则为Native方法服务。

4、堆(线程共享)

创建的对象和数组都保存在Java堆内存中,也是垃圾收集器进行垃圾手机的最重要的内存区域。现代VM采用分代手机算法,从GC角度还可分为新生代和老年代

5、方法区(线程共享)

即我们说的永久代,用于存储被JVM今安在的类信息、常量、静态变量、即时编译器编译后的代码等数据HotSpot VM把GC分代收集扩展至方法区,即使用Java堆的永久代来实现方法区,这样HotSpot的垃圾收集器就可以像管理java堆一样管理这部分内存,而 不必为方法区开发专门的内存管理器。
运行时常量池:是方法区的一部分。用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池。

二、垃圾收集算法

1、标记清除算法(Mark-Sweep)
在这里插入图片描述

最基本的算法,分为两个阶段,标记和清除。标记阶段标记出所有要回收的对象,清除阶段回收被标记对象占用的空间。
问题:内存碎片化严重

2、复制算法(copying)
在这里插入图片描述

为了解决Mark-Sweep算法内存碎块化严重被提出,将内存划分为相等的两块,每次只使用其中一块,当一块内存存满后将存活的对象复制到另一块上,把已经使用的内存清除。
问题:内存被压缩到了原来的一半。存活对象增多,Copying算法的效率会大大降低

3、标记整理算法(Mark-Compact)
在这里插入图片描述

综合以上两个算法,为了避免缺陷提出。标记阶段和Mark-Sweep算法相同,笔记后不清理对象,而是将存活的对象移向内存另一端,然后清除端边界外的对象

三、JVM运行时内存

在这里插入图片描述

Java堆从运行角度可分为新生代(Eden区、FromSurvivor区和To Survivor区)和老年代。其中老年代占堆空间的2/3,新生代占堆空间的1/3,新生代中的Eden占新生代的8/10,from和to各占1/10

四、GC过程

新生代使用复制算法,老年代使用标记整理算法

五、如何判断垃圾

1、引用计数器法

一个对象如果没有任何与之相关的引用,即他们的引用计数都不为零,则说明对象不太肯再被用到,那么这个对象就是可回收的对象

2、可达性分析

为了解决引用计数器法的循环引用问题,Java使用了可达性分析的方法·。通过一些列GC roots对象作为起点搜索。如果再”GCroot“和一个对象之间没有可达路径,则称为该对象是不可达的。
注意:不可达对象不等于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后任然是可回收对象,则面临回收。

六、Java中的引用

1、强引用

最常见,把一个对象赋值给另一个引用变量。此时它处于可达状态,不能被垃圾回收机制回收,即使该对象以后永远不会被使用也不会被JVM回收,因此强引用时造成Java内存泄漏的主要原因之一。

2、软引用

软引用需要使用SoftReference类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时被回收,软引用通常在对内存敏感的程序中。

3、弱引用

需要使用WeakReference类来实现,比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制运行,不管JVM是否有足够的内存空间,总会回收该对象占用的内存

4、虚引用

需要使用PhantomReference类来实现,不能单独使用,必须和引用列队联合使用。主要作用时跟踪对象被垃圾回收的状态

七、垃圾收集器

在这里插入图片描述
1、Serial垃圾收集器(单线程,复制算法)

2、ParNew垃圾收集器(Serial+多线程)
3、Parallel Scavenge 收集器(多线程复制算法、高效)
4、Serial Old收集器(单线程标记整理算法)
5、Parallel Old收集器(多线程标记整理算法)
6、CMS收集器(多线程标记清除算法)
7、G1收集器

八、JVM类加载机制

在这里插入图片描述
1、加载

在内存中生成一个代表这个类的java.lang.class对象,作为方法去这个类的各种数据入口

2、验证

确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,保证不会危害虚拟机

3、准备

在方法区中分配变量的内存空间

4、解析

虚拟机将常量池中的符号引用替换为直接应用的过程

5、初始化

开始执行类中定义的Java程序代码

九、类加载器

在这里插入图片描述
1、启动类加载器(Bootstrap ClassLoader)

负责加载%JAVA_HOME%/lib目录中,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可的类

2、扩展类加载器(Extension ClassLoader)

负责加载 %JAVA_HOME%jre/lib/ext路径下的jar包,或通过java.ext.dirs系统变指定路径中的类库

3、应用程序类加载器(Application ClassLoader)

负责加载用户路径classpath上的类库。

4、自定义类加载器(UserClassLoader)

通过继承java.lang.ClassLoader实现自定义的类加载器。

十、双亲委派模型

1、当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每层都是如此,因此所有请求都会被传宋到启动类加载。只有当父类加载器反馈自己无法完成这个请求时,子类加载器才会尝试自己去加载。
2、不论那个类加载器加载这个类,最终都会委托给最顶层的启动类加载器,这样保证了使用不同的类加载器最终得到的都是同样一个Object对象。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!