1. JVM运行时内存结构

2.JVM学习目录
面试JVM通关:https://blog.csdn.net/qq_31463999/article/details/87966505
总结:内存结构,类加载过程,垃圾回收,jvm调优工具,实战调优
栈+堆+方法区的交互关系
操作数栈可以是任意的java数据类型

我是这么理解 int a= 5; a保存在栈,5在方法区
Student a= new Student() Student保存在堆,a保存在栈
栈可以保存任意的java类型。
1内存结构(内存模型)
上面已经介绍了
补充:
PC寄存器:
我们知道对于一个处理器(如果是多核cpu那就是一核),在一个确定的时刻都只会执行一条线程中的指令,一条线程中有多个指令,为了线程切换可以恢复到正确执行位置,每个线程都需有独立的一个程序计数器,不同线程之间的程序计数器互不影响,独立存储。
注意:如果线程执行的是个java方法,那么计数器记录虚拟机字节码指令的地址。如果为native【底层方法】,那么计数器为空。这块内存区域是虚拟机规范中唯一没有OutOfMemoryError的区域。
栈:
对象的引用(其中的一部分)
每个方法被执行的时候都会创建一个栈帧用于存储局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用的过程就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。【栈先进后出,下图栈1先进最后出来


本地方法栈:

本地方法栈是与虚拟机栈发挥的作用十分相似,区别是虚拟机栈执行的是Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的native方法服务,**可能底层调用的c或者c++,**我们打开jdk安装目录可以看到也有很多用c编写的文件,可能就是native方法所调用的c代码。
方法区:(线程共享的)
用于存储已被虚拟机加载的类信息、常量、静态变量,如static修饰的变量加载类的时候就被加载到方法区中

运行时常量池
是方法区的一部分,class文件除了有类的字段、接口、方法等描述信息之外,还有常量池用于存放编译期间生成的各种字面量和符号引用。
堆:对象存在堆中、分为新生代和老年代(线程共享的)
存放对象实例,也就是常说的java堆内存。
2类加载深入解析
参考:https://blog.csdn.net/qq_31463999/article/details/87931709
类加载:类加载器实际上就是将class文件加载到虚拟机的内存的过程。
加载:在硬盘上查找并通过IO读入字节码文件

找到.class; 转化为jvm运行时内存结构保存在方法区 ;生成java.lang.class对象保存在堆中
连接:
1执行校验: 校验字节码文件的正确性 文件格式、字节码、等符合一些规范
2准备:给类的静态变量分配内存,并赋予默认值(后面一步才会赋值) 静态变量分配内存并赋默认初值(0值或null值)。如static int a = 100;静态变量a就会在准备阶段被赋默认值0。
3解析:类装载器装入类所引用的其他所有类 把类符号引化为直接引用。
初始化:对类的静态变量初始化为指定的值,执行静态代码块 当用到该类时就初始化。
来一个完成功能图,有不对的地方感谢指正



可以参考
https://blog.csdn.net/qq_31156277/article/details/80188110
类加载器种类
启动类加载器:负责加载JRE的核心类库,如jre目标下的rt.jar,charsets.jar等
扩展类加载器:负责加载JRE扩展目录ext中JAR类包
系统类加载器:负责加载ClassPath路径下的类包
用户自定义加载器:负责加载用户自定义路径下的类包

委派:父类加载,找不到则子类加载。修改class文件后,重启JVM才能生效(缓存机制的应用)。先从缓存找如果要使用的时候。

双亲委派模式:
指先委托父类加载器寻找目标类,在找不到的情况下在自己的路径中查找并载入目标类
3垃圾回收机制
问题一什么是垃圾?
答:所谓垃圾回收机制就是对一些不用的对象所占用的内存空间进行回收。那么现在有两个问题一:怎么判断它是不是垃圾(在JVM中回收java对象所占用的空间)?
两种方法:
1,引用计数方法。当JVM中有new 对象时,会分配一个内存空间给它,当有引用时计数为1。如果object ob1=new object(); object ob2=new object(); obj2=obj1;此时obj2的引用就会计数为0。此时2就是被回收的对象。优点:它效率高,快。缺点:循环引用时则不能被回收。
2,可达性分析法。通过一系列的GC-ROOTs对象作为起点进行搜索,如果GC-ROOTS和对象没有可达的路经,则对象不可达的。
GC-ROOTS对象有哪些?

问题二:如何回收(算法)?
在确定了哪些是需要被回收的之后就要做如何回收,如何高效的回收了。
1,标记清除算法:
优点:简单,容易。缺点:会有内存碎片,到时候有大的对象时不好分配。
2,复制算法:
内存分为两块,每次用一块。当要回收时候,将存在的对象复制到另一块去,然后在清除已用的内存。优点:简单,高效,没碎片内存。缺点:内存空间使用上没有合理应用。
3,标记整理法:
将存在的对象向一边移动,清除一边的对象。
4,分代收集算法:
将堆分为老、新代。老的(老-少-):标记整理算法。新的(新-多-有用的少-复制):复制算法。注意:还有一个区是永久代,存储类,方法,常量。回收废弃的常量和无用的类。

知识扩展
方法区、运行时常量池、永久代、元空间。
1:方法区存储的是类的一些基本信息,例如常量、静态变量等。
而,
HotSpot VM把GC分代收集扩展至方法区, 即使用Java堆的永久代来实现方法区, 这样 HotSpot 的垃圾收集器就可以像管理 Java 堆一样管理这部分内存,而不必为方法区开发专门的内存管理器(永久带的内存回收的主要目标是针对常量池的回收和类型的卸载, 因此收益一般很小)。
2,运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版
本、字段、方法、接口等描述等信息外,还有一项信息是常量池。
3、永久代也是存储那些信息的。
4、元空间,

堆内存分布情况

MinorGC - 复制算法过程 (新生代

默认15会被移动到老年代中
MajorGC - 标记清除算法(老年代

不回收(永久代

JAVA8(元空间

分代收集算法:CMS
新生代:复制算法
老年代:标记清除 or 标记整理算法

初始标记->并发标记(和用户一起)->重新标记->标记清除(和用户一起)

CMS回收过程

何时会stopWord?
垃圾回收时的,初始标记和重新标记。
偏向锁取消时候,因为要获取所有线程的状态。
分区收集算法:G1

G1目标是避免FULL GC,精准控制回收时间。

G1的 YONG GC时的STW
存活的对象被转移到一个/或多个survivor 块上去。 如果存活时间达到阀值,这部分对象就会被晋升到老年代。
此时会有一次 stop the world暂停,会计算出 Eden大小和 survivor 大小,用于下次young GC。统计信息会被保存下来,用于辅助计算size。比如暂停时间之类的指标也会纳入考虑。
这种做法使得调整各代区域的大小变得很容易,根据需求可以让他们变大一些或变小一些。
回收过程详解:https://blog.didispace.com/step-by-step-g1/
Full - GC (触发条件

线上CPU100%怎么排查:
- 使用阿里的Arthas:查看服务,查看线程PID,定位代码
https://www.cnblogs.com/stormlong/articles/11439110.html - 使用jstack命令top pid 查看线程pid ,grep二进制的pid查看代码。
https://www.cnblogs.com/stormlong/articles/11439110.html
线上服务突然OOM怎么排查:
- jmp命令查看服务的相关对象信息,每个实例的内存大小,个数等等。
- dump文件到本地使用jvisualVM来进行分析。
本文深入探讨JVM内存结构,包括栈、堆、方法区的概念与交互,类加载过程及垃圾回收机制。解析JVM内存模型,类加载器种类与工作原理,以及垃圾回收算法如标记清除、复制算法等。

1673

被折叠的 条评论
为什么被折叠?



