宋红康GC134-195
基础信息:魔数,字节码文件对应的java版本号,访问表示public final以及父类和接口
常量池:保存了字符串常量,类或者是接口名,字段名,主要在接口中使用
字段:当前类或者是接口声明的字段信息
方法:当前类或者接口声明的方法信息,字节码指令
属性:指的是类的属性,源码的文件名以及类的列表
一)JVM是如何运行的?
1)在程序运行前先将JAVA代码转化成字节码文件也就是class文件,JVM需要通过类加载器将字节码以一定的方式加载到JVM的内存运行时数据区 ,将类的信息打包分块填充在运行时数据区;
2)但是字节码文件是JVM的一套指令运行规范,并不能直接交给底层的操作系统来执行,因此需要特殊的命令解析器,也就是JVM的执行引擎会将字节码翻译成底层的操作系统指令也就是0 1的二进制操作系统指令数据交给CPU执行,因为操作系统只认机器码,不认识字节码
3)执行引擎在进行执行的过程中也会调用其它语言的接口,比如说调用本地库接口调用本地方法来实现整个程序的运行;
4)JVM=类加载器+运行时数据区+执行引擎+本地库接口
类加载器:加载class字节玛的内容到内存中
运行时数据区:负责管理JVM使用到的内存,比如说创建对象和销毁对象
执行引擎:将字节码文件中的内容解析成机器码,同时使用即时编译优化性能
本地方法接口:调用本地已经编译的方法,比如说虚拟机中已经提供好的C/C++的方法
二)JVM的内存布局+JVM的运行时数据区+Java的内存布局
<<java虚拟机规范>>白皮书是给JVM开发厂商去看的,指导开发厂商实现JVM,默认的JVM是hotSpot
1)程序计数器 :当前线程执行的字节码指令的地址,CPU的个数有限,但是任务很多,CPU会频繁进行线程切换,某一块程序会一直经历执行,暂停,再继续执行,就需要有个东西来记录当前线程执行到哪一步,用于存储当前线程执行的执行的字节码的指令的地址,在多线程环境下,程序计数器用于实现线程切换,保证线程恢复执行的时候能够继续从正确的位置开始执行代码
**2)JAVA虚拟机栈:用于存储JAVA方法调用和局部变量(方法内部调用的变量),**局部变量的生命周期是和方法的生命周期是一模一样的,当方法执行完成,方法调用出栈,局部变量也会销毁,为什么JAVA虚拟机栈也是线程私有的呢?因为线程执行方法的局部变量只会有线程本身使用,当前线程执行方法的局部变量,其他线程是不会使用到这个变量,使用到这个方法
**3)本地方法栈:**字符串常量池的底层实现是依靠C++的map来实现的,C++的hashmap也是需要存放局部变量的,存放C++本地方法的方法调用和局部变量
4)堆:对象和数组
5)方法区:类的结构字段方法,静态变量常量,常量池,类里面有几个方法记录的是类原信息
JMM:一种内存模型,为了提升CPU的读写效率, 充分利用CPU资源三)堆和栈有什么区别?
1)存放的数据内容不同
2)大小不同
3)访问数据性能不同:因为堆很大,进行查询对象的时候需要进行寻址和内存管理 ,但是栈存放基本数据类型,内存固定,不需要有动态数据的变化,不需要进行访问,再多大部分情况下,从栈上面寻找数据是很快的,不需要寻址和内存管理;
4)功能侧重点不同 :堆是JAVA虚拟机的主要存储单位,JAVA中的对象和数组都是保存在这个区域的,而栈式JAVA虚拟机基本的运行单位,也就是说,堆主要解决的是数据的存储,数据怎么放,放在哪里的问题,但是栈主要解决的是JVM程序运行的调用关系;
四)方法区和永久代有什么区别?
方法区是JAVA虚拟机规范时候给的一个概念,包括JAVA虚拟机的运行时数据区
但是Hotspot针对于方法区的实现给出了不同的名称
JDK1.7永久代=方法区实现,但是JDK1.8元空间=方法区实现
方法区是定义的名称,但是永久代和元空间都是方法区的实现而已
五)JDK1.8方法区有什么优化?
1)将元空间改成了直接内存
2)将字符串常量池移动到了堆上
在JAVA开发中最常用的两个类型就是对象和String类型,字符串常量池比较大,最大的地方就要放在运行数据区的堆空间上
六)字符串常量池是怎么实现的?
谈谈对Java中符号引用和引用的理解 - 知乎 (zhihu.com)
直接引用:根据内存地址可以直接拿到对象的引用,直接可以定位到字面量的引用地址
符号引用:直接进行编译,还没有进行类加载,就是一个占位符,标记着内存的一个位置
字面量:实际的字符串,判断字符串常量池是否存在该字符串的依据,如果key存在,那么直接就把value值赋值给实际的引用,如果没有就现存
从HotSpot虚拟机来说,字符串常量池是依靠C++的HashMap来实现的,key是字符串常量的字面量,value是字符串对象的引用
编译期常量池:在编译期间可以确定的常量
运行期常量池:在运行期间可以确定的常量,String的intern()方法,将动态生成的东西就是放在运行期常量池的
1)严重性:内存溢出>内存泄漏: 比如说ThreadLocal没有调用remove2)内存泄漏最终会导致内存溢出,而内存溢出可能是内存泄漏导致的,比如说网络IO未释放资源
类加载的过程?==类的声明周期从下向上甩锅,从上向下查询
Serial和Serial old单线程垃圾回收器
ParNew针对于单线程的升级版本是多线程的垃圾回收器:
Parallel Scavenge/Parallel Old:吞吐量优先的垃圾回收期,以回收内存为主,速度比较低,这个垃圾回收器只是保证了吞吐量,但是实际程序是让用户有最少的等待时间
CMS:垃圾回收器 ,可以保证最小的等待时间,就是快,不影响用户久等,不需要将垃圾全部清除掉,多进行几次GC不就行了嘛,需要手动指定
为什么CMS和ParNEW不能一起用,设计理念不同
G1:可控垃圾回收时间的垃圾回收器(JDK 9以后HotSpot默认的垃圾的回收器)
分成多个区,为什么分区算法是可控的?因为分区算法里面有很多区,再进行垃圾回收的时候,假设一共有4个区,他不会保证在这一次GC将A B C D四个区域的垃圾全部回收,而是保证的是可控时间,但是会保证时间到了就罢工,如果时间允许的话,G1垃圾回收器会多回收几个区域,如果时间不允许,我少干一点活,到点就下班;
分代算法为什么时间不可控?
ZGC:停顿时间极短,不超过10ms情况下尽量提高垃圾回收吞吐量的垃圾回收器
JVM(一)
辅助东皇燕双鹰2023-10-11 19:52
相关推荐