jvm重点

java虚拟机

软件模拟的电脑。

吧java的字节码转换成操作系统/cpu能识别的二进制指令

jvm需要做的事情:

1.类加载

2.执行引擎(解释执行字节码)

3.动态内存管理(申请内存/释放内存(垃圾回收))

jvm的内存区划划分

在这里插入图片描述

堆:new 的对象

方法区:类对象 java=》.class二进制字节码 运行的时候加载到内存中(方法区) 是反射的力量来源

​ 1.类有哪些属性 分别叫什么名字 什么类型

​ 2.类有哪些方法 什么名字 什么参数

​ 后面new这个类对象的时候 会根据类对象来决定分配内存的多少

​ 条用某个方法的时候从方法区读取

​ 3.静态成员

栈:jvm栈和本地方法栈

​ jvm代码调用栈 jvm内部c++代码调用栈

程序计数器:cpu执行的时候就会根据程序计数器的值从内存中读取对应的指令到cpu

jvm可以配置堆有多大栈有多大

通过 -xss配置栈 StackoverflowExecption 是否无限递归

通过-xmx -xms 配置堆大小 outofmemoryExecption 排查代码占用是否合理

垃圾回收

内存管理

什么时候申请内存 new对象

什么时候释放内存 仔细分析代码 啥时候不用对象了就可以释放

自动判断对象是否应该回收,

内存不释放 内存可能会泄露 剩余内存变少 申请不到新的内存程序可能崩了

客户端程序内存泄漏问题不大 服务器程序内存泄漏就很严重

内存泄漏不必重启电脑 重启程序即可

一个真实的项目很难避免内存泄漏 (泄漏慢 也还好 例行重启(定时任务 来重启))

栈上的内存 不用垃圾回收 方法的结束(栈帧就会销毁 局部变量就在这个栈帧)

释放以对象为单位 不是字节为单位

不是立刻回收 需要消耗一些资源 STW(stop the world)问题 影响程序的性能

两种手段(引用计数(java没用) 可达性分析)

引用计数

给对象增加一个计数器,每次引用对象计数器加一,引用被销毁计数器-1 没有引用就是垃圾

优点:引用计数下内存回收更加及时

缺点:引用计数+±-操作必须线程安全 多线程就要加锁 低效(python 引入了Gil 全局解释器 )

​ 可能出现循环引用的出现。

static class T{
		public T t=null;
}
public static void main(String[] args){
    T t1=new T();
    T t2=new T();
    t1.t=t2;
    t2.t=t1;
}

可达性分析

从GCRoots出发 一旦某对象不可达 对象持有的引用指向也不可达

jvm专门的线程 定期扫描对象之间的引用关系(图状结构)识别那些对象不可达

GCRoot

栈上的局部变量表中的引用

常量池中引用指向的对象

方法区中静态的引用类型的属性

一个和引用相关的面试题

java中的四中引用:

1.强引用:(平时用的)既可以找到对象也能决定对象的生死

2.软引用: 只能找多对象 一定决定对象的生死(延缓对象回收时机)

3.弱引用: 不能决定生死

4.虚引用: 不能找到对象 不能决定生死 特殊情况下进行善后

如何回收

GC里面的算法思路

1.标记清除

先标记垃圾 再清理

释放标记的对象的内存 缺点:可能会产生很多的内存碎片

2.复制算法

解决内存碎片问题 将内存分为两部分 只适用一部分 把不是垃圾的对象复制到另外一半 这边全部回收

具体是垃圾多还是保留对象多 场景不一样 只适合垃圾多的 浪费内存空间

3.标记整理

​ 类似顺序表删除中间元素一样 没有内存碎片 空间利用率高

​ 内存搬运频繁 效率不高

4.分代回收

​ 分为新生代 老年代

​ 经验规律: 对象存活的越久 就认为对象会继续更久存活下去

存活时间:根据躲过GC的伦次 (jvm周期性可达性分析)

新的对象诞生在伊甸区 新对象大部分活不过一轮

熬过一轮进入幸存区

幸存区的对象也会GC考验 两个幸存区相互配合 使用复制算法 反复进行

幸存区中经历重重GC之后晋升老年代对象 回收率大大降低

大的对象直接进入老年代 不适合幸存区来回复制

术语

particial GC 部分内存区域垃圾回收

FULL gc 全部内存回收

minor gc 针对新生代区域

major gc 大部分区域回收 新生代 +老年代

垃圾回收器 java11就没了 后面引入了更强大的

在这里插入图片描述

评价的好坏

回收的空间效率:扫一遍地 能扫出多少垃圾

回收的速度:扫地时间

是否允许和应用程序并行

是否是多线程的

回收的时间是否可以预测

类加载

将.class内容加载到内存中,

加载的步骤:

1.找到.class文件,解析.class文件格式(jvm规范文档中) 读取到内存

2.链接:类和类之间需要配合 把需要依赖的类进行加载

3.初始化:对类对象进行初始化(初始化静态成员 执行静态代码)

最终得到类对象 通过.class获取类对象

类加载流程: 初始化流程

双亲委派模型 如何找到.class文件

双亲 指的是父亲或母亲

类加载工作的 模块称为“类加载器”

很多类加载器一起工作默认有父子关系 只有一个父亲

jvm默认的类加载器 三个

爷爷 BootstrapClassLoader 加载jdk标准库中的类

儿子 ExtensionClassLoader 加载jvm扩展出来的类

孙子 ApplicationClassLoader 加载用户自定义类的加载器

给定一个类名

给定一个类名~ “java.lang.String”
先由ApplicationClassLoader进行查找,并不会立刻就去负责的目录中找而是先问问父亲ExtensionClassLoader,看着父亲能不能找到.
ExtensionClassLoader也不会立即去负责的目录中找,而是问问他的父亲
BootstrapClassLoader .没父亲了,只能自己找找~发现能够找到java.lang.String~,然后后续就进行加载
如果是加载com.bit.String (咱们自己写的类)
先由ApplicationClassLoader进行查找,并不会立刻就去负责的目录中找而是先问问父亲ExtensionClassLoader,看看父亲能不能找到.
ExtensionClassLoader 也不会立即去负责的目录中找,而是问问他的父亲BootstrapClassLoader .没父亲了,只能自己找找~

防止自己定义的类和标准库冲突

JVM默认是这么玩的.
如果咱们自己写一个类加载器,并且注册到JVM中,
刻就去负责的目录中找而是先问问父亲ExtensionClassLoader,看看父亲能不能找到.
ExtensionClassLoader 也不会立即去负责的目录中找,而是问问他的父亲BootstrapClassLoader .没父亲了,只能自己找找~

在这里插入图片描述

防止自己定义的类和标准库冲突

JVM默认是这么玩的.
如果咱们自己写一个类加载器,并且注册到JVM中,
可以遵守这个模型,也可以不遵守~比如Tomcat,加载 webapps 中的Servlet就没有遵守双亲委派模型~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

力争做大牛的小王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值