对java的理解
-
平台无关性
-
GC
-
语言特性
-
面向对象
-
类库
-
异常处理
平台无关性
编译 javac
运行 java
反汇编 javap -c
javac编译xxx.java文件,生成xxx.class文件,JVM解析,转换成特定平台的执行指令
中间字节码在不同平台上,再次执行不需要检查,
可以将别的语言解析成字节码,JVM再去解析
JVM(内存结构模型,GC)
屏蔽底层操作系统的不同,字节码文件可以在多种平台上运行,是内存虚拟机
Class Loader:依照特定格式,加载class文件到内存
Execution Engine:对命令进行解析
Native Interface:融合不同开发语言的原生库为java所用
Runtim Data Area:JVM内存空间结构模型
反射
在运行态时,任意类可以知道自己的所有属性和方法,任意对象都可以调用自己的任意方法和属性,该功能为java反射机制
反射就是将.class中的成分映射成相应的对象
class:类对象
Constructor:类的构造器对象
Field:类的属性对象
Method:类的方法对象
获取class对象:Class.forName(),xxx.class,objectname.getClass()
获取对象实例:class.getDeclaredConstructor().newInstance()
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获取类对象
//知道类路径
Class<?> rc = Class.forName("reflect.Robot");
//明确类
Class<?> class1 = Robot.class;
//有对象实例的情况
Class<?> class2 = new Robot().getClass();
System.out.println("class name is " + rc.getName());
//创建实例 需有无参构造函数
Robot robot = (Robot) rc.getDeclaredConstructor().newInstance();
robot.sayHi("公有方法可以调用");
//获取所有权限的,特定方法,除继承的方法,方法 + 参数
Method hello = rc.getDeclaredMethod("hello",String.class);
//设置是否调用私有方法
hello.setAccessible(true);
Object object = hello.invoke(robot,"私有方法调用+getdeclaredMethod");
//获取公有特定方法
Method sayHi = rc.getMethod("sayHi", String.class);
//调用
sayHi.invoke(robot,"getMethod");
//私有属性调用
Field name = rc.getDeclaredField("name");
name.setAccessible(true);
name.set(robot,"zhangsan");
sayHi.invoke(robot,"getDeclaredField");
}
ClassLoader
工作在类加载阶段
- 从系统外部获得Class二进制数据流
- 所有Class都是由ClassLoader进行加载
- ClassLoader负责通过将Class文件里的二进制数据流装载进系统
- 然后交给java虚拟机进行连接,初始化等操作
编译器将xxx.java源文件编译为xxx.class字节码文件
ClassLoader将字节码转换为JVM中的Class对象
JVM利用Class对象实例化为xxx对象
ClassLoader的种类
BootStrapClassLoader:C++编写,加载核心库java.*;
ExtClassLoader:java编写,加载扩展库javax.x;
AppClassLoader:java编写,加载程序所在目录,classpath路径下的class文件·;
自定义ClassLoader:java编写,定制化加载;
public class MyClassLoader extends ClassLoader {
private String path;
private String classLoaderName;
public MyClassLoader(String path, String classLoaderName){
this.path = path;
this.classLoaderName = classLoaderName;
}
//用于寻找类文件
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] b = loadClassData(name);
//defineClass 加载二进制class文件流
return defineClass(name,b,0,b.length);
}
//加载类文件
private byte[] loadClassData(String name){
//全路径
name = path + name + ".class";
InputStream in = null;
ByteArrayOutputStream Out = null;
try {
in = new FileInputStream(new File(name));
Out = new ByteArrayOutputStream();
int i = 0;
while ((i = in.read()) != -1){
Out.write(i);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
Out.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return Out.toByteArray();
}
}
双亲委派机制
避免多份同样字节码的加载
图:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
PerfCounter.getParentDelegationTime().addTime(t1 - t0);
PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
内存模型 - jdk8
概念模型:
程序计数器(Program CounterRegister):线程私有,字节码行号指示器,和线程一对一,只为java方法计数,逻辑计数器,不存在内存泄漏
虚拟机栈(Stack):方法执行的内存模型,多个栈帧(局部变量表,操作数栈,动态连接,返回地址)
本地方法栈:用于native方法
元空间(MetaSpace):使用的是本机内存,线程共享,class类
java堆(Heap):对象实例的分配区域,GC管理的主要区域,内有常量池
性能调优参数:
-Xss:线程虚拟机栈的大小-----影响并发线程数的大小
-Xms:堆的初始大小值(一般保持与xmx一致,防止内存抖动)
-Xmx:堆能达到的最大值
内存分配策略:
静态存储:编译时确定存储空间要求(不能有嵌套,可变数据存在)
栈式存储:数据区需求编译时未知,运行时确定
堆式存储:编译和运行时都无法确定,动态分配
堆栈异同点:
堆需要GC回收,栈自动释放
栈空间比堆小
栈支持静态和动态分配,堆只支持动态分配
栈的效率高于堆
流程:
元空间(保存Class类的相关信息,以及System类)-》 java堆(创建类实例,以及常量对象)-》 线程独占(分配程序计数器,虚拟机栈,本地方法栈,保存的是堆内的对象地址引用,和局部变量和行号)
GC
垃圾:没有被其他对象引用
判断算法:
1,引用计数算法:判断对象引用数量,若引用计数器为0,可以被回收,无法监测出循环引用
2,可达性分析算法:判断对象的引用链是否可达,从GC root(栈帧中的本地变量表,方法区的常量引用等) 开始搜索判断
垃圾回收算法:
1,标记-清除算法(Mark and Sweep):
标记:从根集合进行扫描,对存活对象进行标记
清除:对堆内存线性遍历,回收不可达对象内存
缺点:碎片化
2,复制算法(Copying)
分为对象面和空闲面,存活对象被复制到空闲面,对象面被清除
特点:解决碎片化问题,顺序存储,简单高效,适用于对象存活率低的场景
3,标记-整理算法(Compacting)
标记:从根集合进行扫描,对存活对象进行标记
清除:移动所用存活对象,依次排序,末端内存回收
4,分代收集算法(Generational Collector)
垃圾回收算法的组合拳,按照对象生命周期的不同划分区域,采用不同的垃圾回收算法
GC分类
年轻代:尽可能快速的收集生命周期短的对象
Eden区 + 两个Survivor区(8/1,默认年龄为15)
调优参数:
-XX:SurvivorRatio:Eden和Survivor的比值,8:1
-XX:NewRatio:老年代和年轻代内存比例
-XX:MaxTenuringThreshold:对象从年轻代到老年代的最大阈值
老年代:存放生命周期较长的对象
-
Minor GC(复制算法)
-
Full GC(标记整理算法 + 标记清除算法,老年代空间不足,System.gc(),MinorGC晋升到老年代的大小大于老年代剩余大小,自动定时调用)
垃圾收集器
stop-the-world:执行GC而停止程序执行
safepoint:分析过程中对象引用关系不会发生变化的点(方法调用,循环跳转,异常跳转)
JVM client和server运行模式
1,年轻代:
Serial收集器(-xx:+UseSerialGC,复制算法):单线程收集器(收集时,暂停所有工作线程),client模式下默认年轻代收集器
ParNew收集器(-xx:+UseParNewGC,复制算法):多线程收集器,server模式下首选年轻代收集器
ParallelScavenger收集器(-xx:+UserParallelGC,复制算法):多线程,提高吞吐量,server模式下默认年轻代收集器
-XX:+UuserAdaptiveSizePolicy------JVM自适应调节
2,老年代:
Serial Old收集器(-xx:+UseSerialOldGC,标记整理算法):单线程收集,client默认老年代收集器
Parallel Old收集器(-xx:+UseParallelOldGC,标记整理算法):多线程,吞吐量优先
CMS收集器(-xx:+UseCon从MaskSweepGC,标记-清除算法):获取最短回收停顿时间为目标的收集器,三次标记
3,G1收集器(-xx:+UseG1GC,复制+标记-整理算法)----老年代,新生代不再是物理隔离,将java堆内存划分为多个大小相等的Region
并发并行,分代收集,空间整合,可预测停顿
4,ZGC和Epsilon GC(jdk11):
在使用G1的时候,在回收垃圾的时候,必须要保证应用程序当中所有的线程停下来,不在内存中制造混乱,然后GC才会开始工作,会造成停顿。这一个过程,有一个专属名词来解释:STW(stop the world)
ZGC的目标就是缩短STW的时间:ZGC是一个并发,基于region, 压缩型的垃圾收集器,只有root扫描阶段会STW, 因此GC停顿时间不会随着堆的增长和存活对象的增长而变长。
Epsilon GC:开发一个处理内存分配但不实现任何实际内存回收机制的GC, 一旦可用堆内存用完,JVM就会退出。如果有System.gc()调用,实际上什么也不会发生,因为没有内存回收
常用见问题:
1,object.finalize() --------------- JVM回收前调用字段----java9之后已弃用
2,强引用:Object obj = newObject(),如果内存紧张,会终止程序,将对象设置为null弱化引用,使其被回收
3,软引用:对象有用但非必须,内存不足时,GC会回收该引用对象,一般用来实现高速缓存,SoftReference xx = new SoftReference(xxx)
4,弱引用:非必须对象,比软引用更弱,GC时会被回收,WeakReference xx = new WeakReference(xxx)
5,虚引用:起哨兵作用,跟踪对象被垃圾回收器回收活动,必须与引用队列联合使用
6,引用队列:无实际存储结构,存储逻辑依赖内部节点来表达