注意:所有文章除特别说明外,转载请注明出处.
Java底层知识
[TOC]
平台无关性
Java源码首先被编译成字节码,再由不同平台的JVM进行解析,Java语言在不同的平台上运行时不需要进行重新编译,Java虚拟机在执行字节码的时候,将字节码转换成具体平台上的机器指令。
提示:JVM不将源码直接解析成机器码去执行的原因是因为,如果直接解析成机器码执行,那么每次还需要重新检测语法、句法、语义,这样一来整体的性能就会受到影响。
JVM如何加载.class文件
JVM的组成
1.Class Loader 依据特定格式,加载.class文件到内存
2.Execution Engine 对命令进行解析
3.Runtime Data Area JVM内存空间结构模型
4.Native Interface (本地接口) 作用是融合不同的开发语言的原生库为Java所用
Java反射
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。
ClassLoader
类从编译到执行的过程
1.编译器将xxx.java源文件编译成xxx.class字节码文件
2.ClassLoader将字节码转换成JVM中的Class<xxx>对象
3.JVM利用Class<xxx>对象实例化为xxx对象
ClassLoader在Java中有着非常重要的作用,它主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class二进制数据流,它是Java的核心组件,所有的Class都有ClassLoader进行加载,ClassLoader负责通过Class文件里的二进制数据流装载进系统,然后交给Java虚拟机进行连接,初始化等操作。
ClassLoader的种类:
1.BootStrapClassLoader 加载核心库java.*
2.ExtClassLoader 加载扩展库javax.*
3.AppClassLoader 加载程序所在目录
4.自定义ClassLoader
关键函数
findClass
defineClass
ClassLoader双亲委派机制
提示:使用双亲委派机制去加载类的原因:1.避免多份同样字节码的加载。2.
类的加载方式
1.隐式加载 new
2.显示加载 loadClass forName等
类的装载过程
1.加载 通过ClassLoader加载class文件字节码,生成Class对象
2.链接
1.校验 检查加载的class的正确性和安全性
2.准备 为类变量分配存储空间并设置类变量初始值
3.解析 JVM将常量池内的符号引用转换为直接引用
3.初始化 执行类变量赋值和静态代码块
loadClass | forName 的区别
1.Class.forName得到的class是已经初始化完成的
2.Classloader.loadClass得到的class是还没有链接的
Java 内存模型
程序计数器
1.当前线程所执行的字节码行号指示器(逻辑)
2.改变计数器的值来选取下一条需要执行的字节码指令
3.和线程是一对一的关系,即线程私有
4.对Java方法计数,如果是Native方法则计数器值为undefined
5.不会发生内存泄漏
Java虚拟机栈
1.Java方法执行的内存模型
2.包含多个栈帧
局部变量表:包含方法执行过程中的所有变量
操作数栈:入栈、出栈、复制、变换、产生消费变量
JVM性能调优
1.JVM三大性能调优参数
-Xms
规定每个线程虚拟机栈的大小 (堆栈)
-Xmx
堆的初始值
-Xss
堆能达到的最大值
Java内存中堆和栈的区别(内存分配策略)
1.静态存储:编译时确定每个数据目标在运行时的存储空间需求
2.栈式存储:数据区需求在编译时未知,运行时模块入口前确定
3.堆式存储:编译时或运行时模块入口都无法确定,动态分配
堆和栈的联系:
1.引用对象、数组时,栈里定义变量保存堆中目标的首地址
在栈内存中存的地址(指向对应堆内存空间),在堆内存中存的是new出来的对象实例和数组
2.管理方式:栈自动释放,堆需要GC
3.空间大小:栈空间大小比堆小
4.碎片相关:栈产生的碎片远小于堆
5.分配方式:栈支持静态和动态分配,而堆仅支持动态分配
6.效率:栈的效率要比堆高
Java垃圾回收机制
可达性分析算法
1.可以作为GC Root的对象
1.虚拟机栈中引用的对象(栈帧中的本地变量表)
2.方法区中的常量引用的对象
3.方法区中的类静态属性引用的对象
4.本地方法栈中JNI(Native方法)的引用对象
5.活跃线程的引用对象
2.垃圾回收算法(不再做笔记)
1.标记-清除
2.复制
1.解决碎片化问题
2.顺序分配内存,简单高效
3.适用于对象存活率低的场景
3.标记-整理
4.分代收集
1.GC分类:
1.Minor GC
2.Full GC
2.年轻代:尽可能快速地收集掉那些生命周期短的对象
1.Eden区
2.两个Survivor区
3.对象晋升到老年代
1.经历一定Minor次数依然存活的对象
2.Survivor区或Eden区中存放不下的对象
3.新生成的大对象(-XX:+PretenuerSizeThreshold命令控制对象大小)
4.常用性能调优参数
1.-XX:SurvivorRatio:Eden和Survivor的比值,默认8:1
2.-XX:NewRatio:老年代和年轻代内存大小的比值
3.-XX:MaxTenuringThreshold:对象从年轻代晋升到老年代经过GC次数的最大阈值
4.老年代:存放生命周期较长的对象
5.触发Full GC的条件
1.老年代空间不足
2.永久代空间不足
3.Minor GC晋升到老年代的平均大小大于老年代的剩余空间
4.调用System.gc()
6.stop-the-world
1.JVM由于要执行GC而停止了应用程序的执行
2.任何一种GC算法中都会发生
3.多数GC优化都是通过减少stop-the-world发生的时间来提高性能优化
7.safepoint
1.分析过程中对象引用关系不会发生变化的点
2.产生safepoint的地方:方法调用、循环跳转、异常跳转等
3.安全点的数量要适中
常见垃圾收集器
1.JVM的运行模式
1.Server 启动较慢,启动之后程序运行较快
2.Client 相反地
提示:可以利用 java -version 命令来查看JVM的运行模式
2.年轻代常见的垃圾收集器
1.Serial收集器(命令 -XX:UseSerialGC 命令可以让JVM在年轻代处理垃圾回收,是复制算法)
1.单线程收集,进行垃圾收集时,必须暂停所有工作线程
2.简单高效,Client模式下默认的年轻代收集器
2.ParNew收集器(命令 -XX:UseParNewGC 命令可以让JVM在年轻代处理垃圾回收,复制算法)
1.多线程回收,其余行为特点和Serial收集器一样
2.单核执行效率不如Serial,在多核执行才有优势
3.Parallel Scavenge收集器(命令 -XX:+UseParallelGC 命令...,复制算法)
1.吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)
2.比起关注用户线程停顿时间,更关注系统的吞吐量
3.在多核下执行才有优势,Server模式下默认的年轻代收集器
3.老年代常用的垃圾收集器
1.Serial Old收集器(命令 -XX:+UseSerialOldGC 命令...,标记-整理算法)
1.单线程收集,进行垃圾收集时,必须暂停所有工作线程
2.简单高效,Client模式下默认的老年代收集器
2.Parallel Old收集器(命令 -XX:+UseParallelOldGC 命令...,标记-整理)
1.多线程,吞吐量优先
3.CMS收集器(命令 -XX:+UseConcMarkSweepGC 命令...,标记-清除)
垃圾收集过程:
1.初始标记:stop-the-world
2.并发标记:并发追溯标记,程序不会停顿
3.并发预清理:查找执行并发标记阶段从年轻代晋升到老年代的对象
4.重新标记:暂停虚拟机,扫描CMS堆中的剩余对象
5.并发清理:清理垃圾对象,程序不会停顿
6.并发重置:重置CMS收集器的数据结构
4.年轻代和老年代通用
1.G1垃圾收集器(-XX:+UseG1GC 复制+标记-整理算法)
Garbage First 收集器的特点:
1.并发和并行
2.分代收集
3.空间整合
4.可预测的停顿
5.将整个Java堆内存划分为多个大小相等的Region
6.年轻代和老年代不再物理隔离
7.
GC面试题
1.Object的finalize()方法的作用是否与C++的析构函数作用相同
提示
1.javap -c 对编译之后的.class文件作反汇编操作
2.javac 编译生成字节码 .class 文件
3.