目录
内存分区:
内存溢出:
堆内存的分带:(新生,老年,持久)
对象创建:
垃圾回收:
类加载机制:
个人总结的JVM高频知识点。欢迎观众补充和指正:)
JVM是什么?
JVM(Java Virtual Mechane):即java虚拟机,是java语言的执行者,它使得java有良好的跨平台特性。java程序在执行时,先被编译成字节码,然后字节码在jvm上通过解释器运行。
内存分区:
1、程序计数器:空间小,线程私有。字节码解释器通过改变计数器的值来寻找下一条字节码指令地址。计数器是JVM唯一一个不存在OutOfMemoryError的内存区域。
2、虚拟机栈:线程私有,生命周期和线程一致。每个方法(java代码编译的字节码)执行时都会创建一个Stackframe用于存储局部变量表,操作数,动态链接,方法出口。
3、本地方法栈:线程私有。为JVM使用到的Native方法服务(非java代码)。
4、堆:线程共享。主要存放实例对象和数组等,内部划分多个线程私有的分配缓冲区。堆一般是JVM内存中最大的一块。
5、方法区:属于共享内存区,存储已被JVM加载的类,常量和静态变量,即时编译后的代码等。包含.class文件常量池和运行时常量池(存放字面量和符号引用)。
内存溢出:
*StackOverflowError:线程请求的栈深度大于临界值时抛出,如过度的方法递归调用。
*OutOfMemory:虚拟机栈动态扩展时无法申请到足够内存,或在新建线程时没足够的内存创建虚拟机栈。
堆内存的分带:(新生,老年,持久)
*新生代:存放新生对象,由于频繁创建对象,该带频繁进行GC垃圾回收。分为Eden,ServivorFrom,ServivorTo三个区。
*老年代:比较稳定,GC不频繁。
*持久带:主要存放类和元数据。GC不会在主程序运行时清除持久带信息。
对象创建:
创建过程:首先在常量池中定位类的符号引用,并检测该符号引用的类是否被加载、解析和初始化,若没有则进行类加载,然后在堆中为新对象分配内存,执行构造方法。
垃圾回收:
判断对象是否要被回收:引用计数法(不采用),可达性分析法(引用链)
GC Root可以是:
1、Java虚拟机栈中的引用对象。
2、方法去中JNI(Java Native Interface)引用对象。
3、方法区中的常量,类静态属性中引用的对象。
垃圾回收算法:
*标记清除法:直接标记清除。效率不高,空间会产生内存泄漏(因为无法解决循环引用问题)。故不采用。
*复制算法:将空间分成两块,每次只对一块进行GC,当这块内存用完时,把还存活的对象复制到另一块。解决前一种方法的不足,但空间利用率低。
*分代回收:根据年代制定相应回收算法。(新生代复制,老年代标记清除)
引用和引用队列:
//强引用
String str = new String("abc")
//软引用
SoftReference
//弱引用
WeakReference
*强引用:GC不会回收它,引用保存在栈中,对象在堆中。
*软引用:内存空间不足时会被回收。
*弱引用:只要被GC扫描到就回收。(GC优先级低)
*虚引用:不决定对象的生命周期,在任何时候都能被回收。主要用于跟踪对象被垃圾回收器回收的活动。必须和引用队列联合使用。
引用队列:(欢迎补充)
类加载机制:
类的生命周期(7个):加载-->( 验证-->准备-->解析 )-->初始化-->使用-->销毁
JVM把类从.class文件加载到内存,进行校验,解析,初始化,最终形成可以被JVM直接使用的java类型。(数组不通过类加载器创建,而是JVM直接创建)
*加载:通过类名获取类的二进制流,将这个字节流代表的静态存储结结构转化为方法区的运行时数据结构,在内存中生成java.lang.class对象作为访问入口。
*验证:验证文件格式是否符合当前JVM要求。
*准备:为类分配内存并设置变量初始值
*解析:JVM将常量池内符号引用替换为直接引用。(将字面量换为指针、偏移量等)
*初始化:开始执行类中的java代码。初始化类。
双亲委派机制:一个类加载器收到类加载请求,它先把请求委派父类加载器,只有父类无法加载子类时自己才会加载。



