讲诉JVM

jvm是Java代码运行的环境,他将java程序翻译成为机器可以可以识别的机器码,可以跨平台运行如linuc或者windos

简单说一下我对jvm运行的理解,

首先我们运行程序的时候,类加载器会将类按需加载到元空间/方法区 里面

然后启动线程的时候,jvm就会给每个线程分配一个独立的 ,如果有native方法就会有一个本地方法栈 ,对应的每个线程会有一个 程序计数器 用于记录线程运行状态的,线程运行到每一个方法就会有一个栈帧 ,方法执行完, 栈帧就会被释放,后进先出,当线程运行完成,栈也就释放了

在线程运行过程中,所新建和操作的一下临时对象就就会在中创建然后被引用,当线程执行完成,没有引用的对象,在下一次垃圾回收执行的时候被清理。大体流程就是这样

类的加载 触发:是按需要加载的,当被new到,静态方法或静态成员被访问到,反射操作等就会触发类的加载,

类的加载过程:加载,连接,初始化,使用,销毁

加载 阶段:工具类名将类的字节码通过文件、网络等方式读取到内存中,然后解析加载到方法区/元空间中。

加载阶段完成之后就到连接

连接分为3个步骤,首先是验证,验证字节码结构,语义是否复java约束规范 例如开头是否 cafe babe,验证通过就到准备阶段,给静态变量分配内存,给初始值,常量赋值等

最后是解析阶段,将符合引用替换为直接引用,解析为直接内存地址,链接阶段就算完成了

最后就是初始化 了 ,静态变量初始值,执行静态快

初始化完成就是可以使用了,还有就是就是销毁,虽然这个销毁很少发生 在内存不足full GC的时候 还是有可能被销毁的

类加载过程是按双亲委派模型

因为类的加载器有 启动类加载器,扩展类加载器,应用类加载器,每个加载器各自负责加载不通的类,启动类加载java运行时环境所需的类 如string所在的lang包,list,map所在的util包,IO包等,扩展类加载器就是加载bin/ext目录下的第三方库。应用类加载器就是加载我们写的类的,所谓的双亲委派就是 一个类的加载器收到请求,会先去尝试让父类加载,向上委派,如果父类加载过就不需要再加载,例如应用类加载器收到请求 会委派给扩展类加载器,扩展类加载器又委派给启动类加载器,这样做的好处就是确保安全,避免核心类被加载,避免重复加载保证唯一。

类加载好了,在程序启动线程的适合,jvm就会给线程创建一个

这个栈是线程独有的,线程执行完,栈就会自动释放

在线程的运行过程中每执行到一个方法就会创建一个栈帧, 这个栈帧记录着方法执行的操作和数据。

栈帧保存的数据有,局部变量表操作数栈 (如果加减乘除的结果,操作完成就字符,先先进后出),还有动态链接 (方法内存地址,和引用),方法出口 (方法执行完成只有要干什么)

方法执行完栈帧也就出来了,他们后进先出的

线程运行过程程序计数器记录 着 线程的运行位置,在多线程情况下,上下文切换的适合让程序继续执行。

栈也会内存溢出 只是发生的比较少,还有一个深度不够的异常,就是线程执行的方法太深,如递归,不过这些发生的情况还是很少的。栈就大概这么了

线程的运行过程中 会产生很多的引用对象,这些读写被jvm分配到 中,

堆是jvm最大的一个区域,也是我们最关注的,问题也是最频繁的,处理不当就会产生内存溢出或内存泄漏,

首先是内存分配,对象被创建出jvm有几种内存分配方式

1指针碰撞 ,如果堆的内存充足而且规则连续,就会先数组移动指针一样分配,这个成为指针碰撞,这是简单,快速的

2空闲列表 :就是在内存不规则的情况下,jvm会维护一个空闲内存的列表,然后把对象分散的分配

空间的是否规则要看选用的什么类型的垃圾回收机制,有压缩整理功能的就会有规则的空间
++serial,parNew(没有压缩整理),CMS,G1(sweep)(没有)++

3 本地线程分配缓 存 简称TLAB ,就是给每个线程分配一个独立的堆空间用于,使用完自己的才去使用公共的。

对象的组成包含3部分,对象头,实例数据,补齐填充

对象头主要包含:自身运行的数据,hash码,GC分代年龄,锁状态标志,偏凉锁线程id等

实例数据:就是代码中各种成员变量

补齐填充:占位用的,就是为了补齐数 达到某个整数被,提高CPU的访问效率

堆被分新生代和老年,他们的占比默认是占1/3和2/3,

其中新生代又分为eden区和Survivor区,Survivor又分为s1和s2区,他们的默认比例8:1:1,

在垃圾回收的时候 会先把eden区的回收,然后把存活的对象放到s区,经过多次垃圾回收还存活的对象就会升等到老年区,只有在full gc的时候 老年区才会被回收

进入老年区的情况有以下几种,1就是到达阈值指定的,2到达阈值的大对象,3动态年龄判断,就是s区超过50%之后年龄大但却没有到阈值的,4老年代空间担保机制(每次mionr gc的时候都会先判断老年代剩余空间是否大于新生代的,如果大于就直接gc ,如果小于就会在判断 是否大于每次平均晋升值,如果小于就直接full gc,如果大于就minor gc ,如果值多就会直接放到老年代)

相关推荐
Excuse_lighttime6 小时前
JAVA阻塞队列
java·开发语言·jvm
熙客8 小时前
JVM监控
jvm
Thanwind12 小时前
关于JVM和OS中的指令重排以及JIT优化
java·jvm·jmm
快来卷java15 小时前
JVM虚拟机篇(三):JVM运行时数据区与方法区详解
java·jvm·mysql
Aphelios3801 天前
Java全栈面试宝典:线程协作与Spring Bean管理深度解析
java·开发语言·jvm·spring·面试·职场和发展
M malloc1 天前
【C++奇遇记】C++中的进阶知识(继承(一))
java·jvm·c++
摘星编程1 天前
JVM深入原理(六)(二):双亲委派机制
jvm
李小白661 天前
JavaEE初阶复习(JVM篇)
java·jvm·java-ee
我不想当小卡拉米2 天前
C++:继承+菱形虚拟继承的一箭双雕
开发语言·jvm·c++
时光呢2 天前
JAVA常见的 JVM 参数及其典型默认值
java·开发语言·jvm