目录
一、JVM内存区域划分
二、JVM类加载
三、JVM垃圾回收(GC)
一、JVM内存区域划分
- 栈
- 堆
- 方法区(元数据区)
- 程序计数器
1.栈
举个例子:
那具体是怎么分的呢?如下图
本地方法栈:给JVM内部的方法准备的栈空间
虚拟机栈:给Java代码使用的栈(这里的栈与数据结构的栈的概念不同)
栈是每个线程都有一份,一个进程有n份
2.堆
堆是每个进程只有一份
3..元数据区
类对象就是在这里,包括常量池,静态成员~~
4..程序计数器
记录当前线程执行到那个指令,每个线程有一份
二、JVM类加载
类加载流程:
对于一个类来说,它的生命周期是这样的:
其中前 5 步是固定的顺序并且也是类加载的过程,其中中间的 3 步我们都属于连接,所以对于类加载来说总共分为以下几个步骤:
1. 加载:把.class文件找到,读取文件内容,最终得到一个类对象
一个类,啥时候会被加载呢?
怎么找到.class文件呢?
双亲委派模型,描述的是就是找.class文件的基本过程 (最常考)
基本流程:
举个例子:
假设用户在自己的代码中,写了个java.lang.String这个类,按照上面的加载流程,此时JVM加载的是标准库中的类,不会加载自己写的类。
2. 连接
1. 验证——根据jvm虚拟机规范、检查.class文件的格式是否符合要求
2. 准备——给类对象分配内存空间(内存初始化为全0)
3. 解析——针对字符串常量进行初始化,把符号引用转为直接引用
把符号引用转为直接引用的意思:
举个简单的例子:
3. 初始化:真正针对类对象里面的内容进行初始化,加载父类,执行静态代码块的代码
三、JVM垃圾回收(GC)
大家还记得吗?在C语言中,我们通过malloc动态申请内存(申请的内存是在堆中),每次申请完后都要我们手动释放内存(free)。如果不释放就回造成内存泄漏等严重问题。
但是如果光指望我们程序员手动释放内存,那显然是不靠谱的。
为在Java中就由机器负责回收不再使用的内存空间——这种机制就被称为内存回收机制(garbage collection简称GC)
GC的好处:非常省心,让程序猿写代码简单点,不容易出错
GC的坏处:需要消耗额外的系统资源,也有额外的性能开销
性能开销导致的问题:STW问题(stop the world)
如果有时候,内存的垃圾已经非常多了,此时触发一次GC机制,开销会非常大,大到可能把系统资源吃了很多~~
另一方面,GC可能会涉及一些锁操作,导致业务没办法正常执行,这样的卡顿,可能会持续几十毫秒或者上百毫秒~~
举个简单的例子:当你在家电脑打游戏时,突然你妈妈过来扫地,那你就只能挂机,站起来等你妈妈扫完这个地方,才继续~~
1.那么,垃圾回收收的是什么呢?
2.如何确定该对象需要回收呢?
- 引入计数【不是java的做法.python/php】
- 可达性分析 【java的做法】
大家面试注意审题:
1.问题是:垃圾回收中如何判断对象是垃圾?
此时两个都说
2.问题是: 谈谈java的垃圾回收中如何判断对象是垃圾?
此时只需要说可达性分析
引入计数 :
大括号结束,上述三个引用超出作用域,失效,此时引用计数就是0了,此时new Test()对象就是垃圾了~~
那为什么java不使用这个方法呢?
可达性分析 :
可达性就是以代码中的一些特殊变量为起点,然后以起点触发,看看哪些对象都能被访问到。只要对象能访问到,就标记为“可达”,当完成一圈标记后,剩下的就是“不可达“的了,也就是要回收的垃圾了。
我们对上面的名词做出解释~
简单来说~~
举个例子:
确定了要回收的对象,那如何进行垃圾回收呢?
1.标记清除
2.复制算法
3.标记整理
4.分代回收