JVM(Java虚拟机)

1. JVM概念

JVM(Java Virtual Machine的简称。意为Java虚拟机)

JVM要做的事情:

  1. 类加载
  2. 执行引擎(解释执行字节码)
  3. 动态内存管理(申请内存/释放内存(垃圾回收)

2. JVM的内存区域划分(面试问题)

1,堆区:通过关键字 new 出来的对象都存放在堆区,也是 JVM 占据空间最大的区域

2,方法区:存放类对象,就是一个.java文件通过 javac 编译成.class的二进制字节码文件,然后程序运行的时候就会把这个.class文件加载到内存中,内存的方法区中(这个过程叫类加载)。
类对象就是描述了每一个类是啥样的,1). 里面有那些属性,分别是什么名字,什么类型,什么访问修饰权限修饰的,是 public 还是 private。2). 里面有那些方法,同上…
后面 new 这个类的实例的时候,就要根据这个类对象来决定在堆区分配多少内存

3,栈区:虚拟机栈描述的是Java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈和出栈的过程。声明周期与线程相同。

4,程序计数器:程序计数器是一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。如果当前线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是一个Native方法,这个计数器值为空。简单理解就是存放了一个内存地址

这玩意只有背!!!

3. JVM的垃圾回收(巨高频考点)

对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言,其生命周期与相关线程有关,随线程而生,随线程而灭。并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回收了。因此关于内存分配和回收关注的为 Java 堆方法区这两个区域。

关于垃圾回收需要考虑两件事,1. 先判断谁是垃圾? 2. 怎么回收垃圾?

判断谁是垃圾?

1. 引用计数

比如有一个对象,创建该对象的同时,给这个对象搭配一个计数器。每次有一个引用指向这个对象,计数器就+1,每次有一个引用被销毁,计数器 -1,当计数器为 0 的时候,这个对象就"没人引用了,自然也就是垃圾了"。

2. 可达性分析(Java中采用的)

Java 里的对象都是通过引用来获取到的,一个引用能指向一个对象,一个对象里可能还包含若干个引用,这个引用关系,就构成了一个"图状结构",类似于树。

可达性分析,从 GCRoots 出发,能够被访问到对象就是“可达的”,不能够访问到的对象是“不可达的",一旦某个对象不可达了,此时就会导致这个对象持有的引用指向的其他的对象也不可达了。如下图

GCRoot(从哪里开始遍历)

1. 栈上的局部变量表中的引用
2. 常量池中的引用指向的对象
3. 方法区中的静态的引用类型的属性

关于 Java 中的四种引用

1. 强引用,既可以找到对象,也能决定对象的生死。(就是平时用的引用)
2. 软引用,能找到对象,只能一定程度的决定对象的生死。(延缓对象被回收的时机)
3. 弱引用,能找到对象,不能决定对象的生死。
4. 虚引用,不能找到对象,也不能决定对象的生死。(只是一些特殊情况,比如进行一些善后工作的时候)
注意:后三种基本用不上。(在标准库里有对应的类表示)

怎么回收垃圾?

1.标记清除
⒉复制算法

把不是垃圾的对象,复制到另外一半内存中,然后回收这整块内存

3.标记整理
4.分代回收

分代回收,主要就是基于一个经验规律:
如果一个对象存活的时间越久,就认为这个对象会继续更久的存活下去。

如何衡量对象的"存活时间"。根据这个对象躲过的GC的轮次。(JVM会周期性的进行可达性分析)给对象引入了“年龄",就是躲过的GC的轮次。

分析步骤:

  1. 新的对象诞生于伊甸区。(新对象的内存在伊甸区上分配)
  2. 有一个经验规律表明,在伊甸区中的新对象,绝大部分都活不过一轮GC(类似于参加笔试)。熬过一轮GC的对象就进入了“幸存区"(类似笔试通过,进入了面试环节)。
  3. 幸存区里的对象,也会经受GC的考验。两个幸存区就相互配合,使用"复制算法"
    ,每次经过GC考验的对象,就被复制算法拷贝到另外一个幸存区,反复进行这个过程(类似每一轮面试都会刷人)。
  4. 在幸存区中经历了重重GC之后,年龄积累到一定程度了,对象就晋升为"老年代对象",把这个对象从幸存区拷贝到了老年代(类似于通过面试进入公司了)。
  5. 老年代的对象不是说就一直不回收,而是回收的频率就大大降低了。(就类似于被裁)

注意:还有一个特例,如果是一个很大的对象,就不适合在幸存区复制来复制去,就
直接进入老年代(类似于走后门)。

分代回收中核心思路:
根据对象的年龄来预测生命周期是长还是短,认为年龄越大,生命周期就会更长。年龄越小,生命周期就越短。

一个对象如何证明自己年龄大?
在伊甸区和幸存区经历一定的摸爬滚打,才能证明

所以一般认为:新生代的扫描频率较高(新生代的对象大概率是垃圾);老年代的扫描频率较低(老年代的对象成为垃圾的概率也低)。

4. 类加载

类加载是干啥,就是JVM把.class 文件内容加载到内存中,内存的方法区中,而方法区里存的就是类对象。

类加载的步骤:

  1. 加载:找到.class 文件,解析.class 文件的格式,读取到内存中。
  2. 链接:类和类之间需要配合(类A实例化了类B),就需要把依赖的类也进行加载。
  3. 初始化:对类对象进行初始化(初始化静态成员,执行静态代码块,代码块,构造方法…)

类加载最终的结果就是得到了"类对象”,在代码中可以通过Test.class这样的方式获取到类对象。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值