JVM

对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,引用队列:无实际存储结构,存储逻辑依赖内部节点来表达

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.Ma.01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值