JVM知识点
概念
Java虚拟机——模拟cpu执行指令的一个程序。
JDK、JRE、JVM关系
java内存模型
线程私有
程序计数器:程序计数器是一块比较小的内存区域,可看做当前线程执行字节码的行号指示器.是线程隔离的
JVM虚拟机栈:每个方法执行的同时会创建一个栈帧用于存储局部变量、操作数栈、动态链接、方法出口等信息。每一个方法从调用直到执行完成的过程,就对应一个栈帧在虚拟机中入栈和出栈的过程。入栈:方法调用。 出栈:方法返回。是线程隔离的
- 和线程相关,不同线程内,即使运行同一个方法,也是处于不同内存。
- 和方法相关,即使是同一个线程,递归调用某个方法,每次调用都会生成该此方法调用的栈帧。
此区域一共会产生以下两种异常:
- 如果线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量),将会抛出StackOverFlowError 异常。–递归返回逻辑有问题
- 虚拟机在动态扩展时无法申请到足够内存会抛出OOM(OutOfMemoryError)异常。—内存溢出
内存溢出和内存泄漏
- 内存溢出:线程调用方法,创建方法该次调用的栈帧,内存不足抛出OOM。应用程序中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存,此时程序运行不了,系统提示内存溢出(进程会挂掉,情况严重)
- 内存泄漏:程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
- 一般出现内存泄漏的情况:长生命周期存活的对象,内部持有不使用对象的引用,导致不使用的垃圾对象无法回收
- 一般经常出现内存泄漏的例子:在使用长期存活的数据结构、数组时,都要考虑对象的引用导致内存泄漏的问题
本地方法栈
调用java方法,就是创建栈帧,放在线程的java虚拟机栈中。
调用其他语言的函数,就是使用本地方法栈
线程共享区域——存在GC
java堆:在JVM启动时创建,所有的对象实例以及数组都要在堆上分配,如果在堆中没有足够的内存完成实例分配并且堆也无法再扩展时,抛OOM(内存溢出)
方法区/元数据区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。此区域内存的回收主要针对常量池的回收以及类型的卸载,当方法区无法满足内存分配需求时,抛OOM
运行时常量池:编译期及运行期间产生的常量被放在运行时常量池。这些所说的常量包括:基本类型、包装类(包装类不包括浮点型,整形只会管理-128~127),类加载时会查询字符串常量池,以保证运行时常量池所引用的字符串与字符串常量池中一致
class文件常量池:class文件除了有类的版本、字段、方法、接口等描述信息,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,类加载后进入
直接内存:在JDK 1.4中新加入NIO(New Input/Output)类,引入了一种基于管道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存引用进行操作,这样能在一些场景中提高性能,避免在java堆和Native堆来回复制。直接内存不会受java堆大小限制,但既然是内存,肯定会受到本机总内存(包括RAM及Swap区或分页文件)大小以及处理器寻址空间的限制,也可能导致OOM
类加载
jvm类加载过程:
类加载机制——双亲委派模型
class字节码文件需通过 类加载器 来加载到java进程的内存。
双亲委派模型:就是基于4种类加载器,按照从上到下的顺序,来加载类。
因为类加载只执行一次,所以,上边的找到,下边就不执行加载;没有找到,就交给下—级的加载
优点: 安全
垃圾回收GC
概念
java语言,是不用程序员自己分配内存,也不用自己回收内存===>原因: jyvm中,实现了垃圾回收的机制(自动回收)
需进行GC的内存区域:堆、方法区
什么是垃圾
如何判断一个对象是垃圾?有两种算法
1.引用计数算法
2.可达性分析算法——JVM采取
垃圾回收算法
新生代/老年代
什么时候发生gc?
对象进入哪个区域(新生代还是老年代),如果该区域空间不足,就会触发该区域的gc
两个gc的特性:
新生代gc:又叫minor gc,采取复制算法,效率比较高
老年代gc: 又叫major gc,采取标记清除/标记整理算法,效率比较差,一般比新生代gc慢10倍以上
1.标记清除算法——老年代回收算法
⒉复制算法——新生代的回收算法
将某个内存区域,划分为两块大小相同的空间,每次只使用其中一个,回收就是把存活对象复制到另一个不用的空间,清除之前使用的空间。
使用场景: 大多数对象,具有朝生夕死的特性。
说明:比如很多方法调用,在方法中使用局部变量=new对象,方法执行完,对象就是垃圾了
3.标记整理算法——老年代的回收算法
过程:
- 标记
- 整理:把存活对象往一端移动,然后清理掉端外的空间
4.分代回收算法——jvm中,采取的算法
内存(堆)划分为新生代(E区 * 1+S区 * 2)和老年代。
新生代采取 复制算法,老年代采取 标记清除/标记整理算法。
垃圾回收器
垃圾回收工作,是由垃圾回收线程(它是守护线程=>一个进程中,还存在非守护线程,进程就不会结束)
概念区分:
(1)可达性分析算法=>判断对象是否是垃圾
(2)垃圾回收算法=>回收垃圾,采取的算法
(3)垃圾回收线程=>垃圾回收工作,就是在垃圾回收线程中执行的
(4)垃圾回收器=>名词,类似开垃圾车的师傅
关联: 在垃圾回收线程中,使用垃圾回收器(垃圾车师傅),先找到垃圾(可达性分析算法),再回收垃圾(采取了什么垃圾回收算法)
前置知识:
jvm中经典的垃圾回收器
各个收集器大致介绍: