各位小伙伴们大家好,欢迎来到这个小扎扎的专栏 总结 | 提效 | 拓展,在这个系列专栏中记录了博主在学习期间总结的大块知识点;以及日常工作中遇到的各种技术点 ┗|`O′|┛
🌆 题目速览
- 1. JVM的位置
- 2. JVM的体系结构
- 3. 类加载器
- 3.1 双亲委派机制
- 3.2 沙箱安全机制
- 4. 运行时数据区
- 4.1 方法区
- 4.2 栈
- 4.3 本地方法栈(native关键字)
- 4.4 堆
- 4.4.1 三个堆内存
- 4.4.2 堆内存调优参数
- 4.4.3 垃圾回收算法
- 4.4.3.1 GC算法——引用计数法
- 4.4.3.2 GC算法——复制算法
- 4.4.3.3 GC算法——标记清除算法
- 4.4.3.4 GC算法——标记压缩算法
- 4.5 程序计数器
- 5. 栈、堆、方法区的调用关系
1. JVM的位置
JVM相当于一种用于运行java程序的虚拟机软件,所有的java程序需要使用JVM才能运行;而JVM需要运行在操作系统上,操作系统也相当于是一种系统软件;操作系统也需要运行在硬件体系之上
jdk、jre、jvm的关系
2. JVM的体系结构
一个java程序从开发到运行的全过程:程序员编写.java文件(源代码文件) ⇒ 计算机使用javac.exe程序
将.java文件编译成.class文件(字节码文件) ⇒ 计算机使用java.exe程序
将.class文件送到JVM中运行 ⇒ 运行的过程中随时向核心类库中调用Java编写好的程序来支撑自己编写程序的运行
JVM虚拟机包含类加载器、运行时数据区以及执行引擎;运行时数据区有包含方法区、栈、本地方法栈、堆、程序计数器
其中栈、本地方法栈、程序计数器在JVM运行的时候都不会产生垃圾,而所谓的JVM调优基本上都是在方法区和栈
中进行调整
3. 类加载器
使用new实例化的对象都存储在堆内存中,变量存储在栈内存中,将实例化后的对象赋值给变量的操作实际上就是将堆内存中的地址引用指向栈中的变量
三大类加载器:
1、引导类加载器(BootstrapClassloader):用C++编写,是JVM自带的类加载器;负责加载Java的核心类库。(该加载器无法直接获取)
2、扩展类加载器(ExtClassloader):负责加载/jre/lib/ext目录下的jar包。
3、应用程序类加载器(AppClassloader):负责加载java -classpath或-D java.class.path所指的目录下的类与jar包。(最常用的加载器)
3.1 双亲委派机制
类加载器接收到一个加载请求时,他会委派给他的父加载器,实际上是去他父加载器的缓存中去查找是否有该类,如果有就加载返回,如果没有则继续委派给父类加载,直到顶层类加载器。如果顶层类加载器也没有加载该类,则会依次向下查找子加载器的加载路径,如果有就加载返回,如果都没有,则会抛出ClassNotFoundException异常。
使用双亲委派机制的好处:避免了类的重复加载,避免核心类库被修改导致的各种异常以及安全问题
3.2 沙箱安全机制
沙箱安全机制实际上就是为了保证java程序的安全性而采取的一种机制措施,主要可以参考链接博客https://blog.csdn.net/IAMZTDSF/article/details/123869863
4. 运行时数据区
运行时数据区包括:方法区、栈、本地方法栈、堆、程序计数器
4.1 方法区
Method Area方法区(此区域属于共享区间,所有定义的方法的信息都保存在该区域)。方法区是被所有线程共享,所有字段、方法字节码、以及一些特殊方法(如构造函数,接口代码)也在此定义。
存放内容:静态变量、常量、类、接口的定义、运行时常量池。
运行时常量池用于存放编译期生成的各种字面量
和符号
的引用
,这些内容(引用)编译时期存储在class文件的常量池中,在类加载后存放到方法区的运行时常量池当中。
1、字面量
int i = 1; 把整数1赋值给int型变量i,整数1就是Java字面量,
String s = “abc”; abc也是字面量。
2、符号的引用
符号引用就是使用一组符号来描述所引用的目标,符号可以是任何形式的字面量, 只要使用时能够无歧义的定位到目标即可。例如, 在Java中一个Java类将会编译成一个class文件,在编译时Java类并不知道所引用的类的实际地址,因此只能使用符号引用来代替。比如org.simple.People类引用了org.simple.Language类, 在编译时People类并不知道Language类的实际内存地址, 因此只能使用符号org.simple.Language来表示Language类的地址.
4.2 栈
栈:先进后出
(类似弹夹);队列:先进先出
(类似排队先到先得),队列特性FIFO(first input first output)
栈又叫作栈内存,主管程序的运行,生命周期和线程同步
;线程结束栈内存也就释放了,所以对于栈来说,不存在
垃圾回收问题。(main方法所在的线程叫做主线程,执行程序的时候main方法最先加载,但是最后结束,main方法执行结束之后主线程也就结束,此时栈内存随之释放)
存放内容:八种基本数据类型、对象的引用,局部变量
栈中存储的是对象的引用,对象本身并不存放在栈中,而是存放在堆(new出来的对象)或者常量池中(字符串常量对象存放的常量池中) 常量池在方法区
方法中的局部变量使用final修饰后,放在堆中,而不是栈中
栈帧
一条线程中的每一个执行或者等待执行的方法在栈中又叫作栈帧,每一个正在执行的方法总是在栈的最上方,方法执行后会被弹栈,通过父帧的指向执行下一个方法,等栈中的所有方法都执行完,也就意味着栈中已经没有栈帧,此时这个栈内存就会被释放。如果栈中被压进了过多的栈帧,就会导致栈满,程序就会出现栈溢出错误StackOverflowError
4.3 本地方法栈(native关键字)
native关键字的使用说明Java的作用范围已经达不到了,它会去调用底层的C语言库
。
调用native关键字修饰的方法时,先进入本地方法栈,然后调用本地方法接口,通过调用JNI接口实现对其他语言代码和代码库的使用。
JNI的作用:扩展Java的使用,融合不同的语言为Java所用(最初是为了融合C、C++语言因为Java诞生的时候,C和C++非常火,想要立足,就有必要调用C、C++的程序)。所以Java在JVM内存区域专门开辟了一块标记区域
–本地方法栈(Native Method Area Stack),用来登记native方法
,在最终执行(执行引擎执行)的时候,通过JNI来加载本地方法库中的方法。
4.4 堆
堆内存在一个JVM中只存在一个,且堆内存的大小是可调节的,我们可以通过调节堆内存的大小来进行JVM调优。
存放内容:实例化对象、字符串常量池。
4.4.1 三个堆内存
堆内存又被分为新生代(伊甸园区+幸存区)、老年代、元空间;jdk1.8之前元空间又被称作是永久存储区。
4.4.2 堆内存调优参数
参数 | 描述 |
---|---|
-Xms | 堆内存初始大小,单位m、g |
-Xmx | (MaxHeapSize) 堆内存最大允许大小,一般不要大于物理内存的80% |
-XX:PermSize | 非堆内存初始大小,一般应用设置初始化200m,最大1024m就够了 |
-XX:MaxPermSize | 非堆内存最大允许大小 |
-XX:NewSize(-Xns) | 年轻代内存初始大小 |
-XX:MaxNewSize(-Xmn) | 年轻代内存最大允许大小,也可以缩写 |
-XX:SurvivorRatio=8 | 年轻代中Eden区与Survivor区的容量比例值,默认为8,即8:1 |
-Xss | 堆栈内存大小 |
4.4.3 垃圾回收算法
4.4.3.1 GC算法——引用计数法
每个对象都会分配一个计数器,用于计算该对象被引用的次数,等到执行GC垃圾清除的时候,将被引用次数不符合要求的当做垃圾进行清除。
4.4.3.2 GC算法——复制算法
幸存区可分为from取和to区
对象通过new实例化后存在伊甸园区中,当伊甸园区中的对象数量达到一个阈值的时候会触发一次轻GC,经过GC仍存在的对象进入幸存from区;所谓的复制算法就是把幸存from区的对象进行GC之后和幸存to区的对象进行交换,然后把名字也进行互换(保证幸存to区里永远没有对象),经过指定次数的GC之后依然存活的对象存入老年区,而这个次数可以使用-XX:MaxTenuringThreshold进行指定
**优点:**没有内存碎片
**缺点:**幸存to区永远没有对象,于是会导致内存空间得到浪费
4.4.3.3 GC算法——标记清除算法
第一次扫描,对仍存活的对象进行标注;第二次扫描,对未标记的对象进行清除
**优点:**不需要额外的空间
**缺点:**两次扫描,浪费时间,产生内存碎片
4.4.3.4 GC算法——标记压缩算法
第一次扫描,对仍存活的对象进行标注;第二次扫描,对未标记的对象进行清除;第三次扫描,进行压缩,把向一端移动防止内存碎片
4.5 程序计数器
程序计数器:Program Counter Register。每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向像一条指令的地址,也即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。
5. 栈、堆、方法区的调用关系
创建对象内存分析,类的定义以及字符串常量池都在方法区中,使用new实例化的对象存在堆中,独享变量存在栈里,通过引用地址指向堆中的实例化对象,对象的字符串属性指向堆中的字符串常量池中