JVM基础
初识JVM
1. JLS:java language specification java语言规范
Jvms java虚拟机规范
2. 最常用的还是hotspot 虚拟机
3. 堆,所有对象都在堆上分配,不是线程私有的
4. 方法栈,线程私有,不会发生线程安全问题,每当有方法调用的时候,就会有栈帧入栈。局部变量在栈帧中分配
5. 栈帧对方法调用的表示,每一次调用都会产生一个栈帧,而不是每个方法产生一个栈帧(递归就是自己调用自己)
6. Java中所有参数的传递都是拷贝,参数一直都是值传递
7. 本地方法栈可能接触不到
8. Jvm只支持全限定类名
9. 对象地址在栈帧中占用的空间取决于操作系统,操作系统时32位那就是32;否则64
10. 1.7前字符串常量池位于方法区,1.7后移到了堆上
11. 方法区在1.7时放在永久代(与堆共享内存,很容易oom),1.8之后在元空间
12. 类加载器:打通类代码和数据之间的障碍?
13. 双亲委派加载模型:当任何一个类加载器尝试加载某个类,都会首先委托给他的父类,如果父类可以加载成功的话,那就直接返回,父类不能加载成功才会让子类的类加载器去加载这个类
使用类加载器的目的
(1) 安全性:不加载恶意的字节码
(2) 越核心的类由越顶层的加载器来加载
(3) instanceOf不仅检查类,也检查类加载器
多线程
14. 方法栈和栈帧?
15. 为什么需要多线程,本质上是cpu/内存/io的巨大性能差异
16. 线程的本质就是一个可以执行代码的工人,但线程开启后执行的顺序就会混乱。
17. thread中每一个实例代表jvm的一个线程,在java世界中,只有thread是线程
18. 异常的抛出是顺着方法栈来的,try catch只会抓住当前线程的异常
19. main线程就是jvm默认的线程
20. runnable和callable,只代表一个任务。
21. callable是runnable的高级版本,可以抛出异常可以有返回值1
22. 线程池:因为线程是一种很昂贵的资源
23. 线程池六个参数?New worker?线程池中会调用新的线程
24. 线程的生命周期
25. thread类中有state
(1)new;还没开始的线程
(2)Runnable;正在jvm中执行的线程
(3)Bolcked;被阻塞并等待monitor锁的线程
(4)Waitting;无限期等待另一个线程,直到调用notify方法
(5)Time_waited;
(6)Terminated;终止
26. 两个线程执行的时候,方法栈上面的局部变量是私有的;但堆不是
27. jvm多线程模型?
28. Volatile 关键字,所有线程对共享变量的修改读取都是主内存的。只保证可见行,不保证原子性。有同步的情况不实现volatile,默认不实现volatile是为了提高执行速度
Cpu 指令重排,分支预测;
29. JUC 并发包
30. 多线程的问题
(1) 正确性
(2) 同步 只有被悲观锁,排他锁,没有乐观锁,共享锁
(3) 协同
31. wait放弃印章,sleep则没有
GC
31. 手动内存管理(C)
32. 引用计数:清除计数为0的;最大的问题就在于如果有循环引用,就无法被清除
33. 标记清除:规定从根节点访问不到的都是垃圾,访问的到的就不是垃圾;
34. 垃圾回收还包括碎片化问题的解决
35. 引用的类型
(1)强引用(Strong):用到的都是强引用
(2)软引用(Soft)
(3)软引用
(4)幻象引用
36. GC发生了什么:
(1)stop the world,时间大概
(2)清除垃圾
(3)压紧内存/拷贝
37. 那些是GCroots
(1) 活着的线程
(2) 类的静态成员
(3) 线程方法所引用的对象
(4) JNI引用的对象
(5) 分代GC时其他代的对象
38. HostPost虚拟机你对象的分代假设(绝大多数对象都死得很快哈哈哈哈)
(1) 新生代:new一个对象,直接进入eden,然后eden满了就放到survivor1/2(只有一个会是满的),然后年龄加一,足够老了就放到老年代里面。发生gc频率高
l 老年代,发生gc频率较低。如果有个对象比较大,可能直接分配到老年代里面
(2) 永久代:java8之前永久到是堆的一部分;一般存储类数据,字符串常量
(3) 元空间:不是堆的一部分,
39. 线程的状态可以在jdk源码中看。
40. Full gc,程序不健康的标准。
41. visualVM可视化jvm的大小
零. 为什么要在jvm中运行:因为jvm听过了科一只行和代码托管环境,java代码编译为java字节码后可以在不同平台的jvm运行,且jvm可以处理部分冗长/容易出错的事务。
一. Java文件的运行
1. 写好.java文件
2. 编译为.class文件
3. JVM需要执行这个文件的话,就用类加载器将.class搬进jvm
4. 类加载器将文件搬到jvm的方法区,方法区存放元数据信息,例如:类信息,常量,静态变量,编译后的代码。
5. 堆主要存放储存的数据,例如对象实例和数组等;方法区和堆都是线程共享区域,也就是说它们是线程不安全的
6. 栈:代码运行空间,每一个方法都在这里运行
7. 程序计数器:作用是完成加载的工作;
8. Jvm分为五大块:虚拟机栈和本地方法栈,堆,程序计数器,方法区;其中堆和方法区是线程不安全的,其余都是线程安全的。
9. 执行main方法的步骤:简单的来说就是对象实例初始化时会去方法栈找类信息,完成后再到栈去运行。
(1) 编译.java(这是个类)得到.class文件,系统启动jvm进程,在classpath路径找到.class文件,并将这个文件对应的类信息加载到方法区内(类加载器在干活儿),这个过程叫做类的加载
(2) Jvm找到上面那个类的主程序入口(main方法)并执行
(3) 执行方法中第一条语句:Student student = new Student(“aa”); ,但方法区没有这个方法,所以jvm需要加载Student类(回到第一步),加载完之后放到方法区中。
(4) 加载完Student类后,JVM会在堆内为Student实例分配内存,并调用构造函数,初始化Student实例,堆里的这个Student实例可以指向方法区中Student类的类型信息???
(5) 然后执行第二行:student.sayName(); jvm根据student的引用找到student对象,然后根据student对象持有的引用定位到方法区中student类的方法表,获取sayName()的字节码地址
(6) 执行sayName()
二. 类加载器
它负责加载.class文件到内存中,然后将内容转化为方法区中的运行时数据结构;
1. 流程
(1) 加载:将class文件加载到内存;将静态数据结构转化为方法区中运行时到数据结构(这是啥意思);在堆中生成java.lang.Class作为数据访问的入口
(2) 连接:验证加载的类是安全的;为static变量在方法区中分配内存空间,并设置变量的初始值;将符号引用替换为直接引用
(3) 初始化:执行构造器方法的<clinit>()(不懂)
(4) 卸载:GC
2. 加载顺序
(1) BootStrap Classloader rt.jar
(2) Extension Classloader 加载拓展的jar包
(3) App Classloader 指定classpath下的jar包
(4) Custom Classloader 自定义的
3. 双亲委派机制
当一个类收到了加载的请求后,它不会自己先去尝试加载,而是委派给父类完成,只有当父类无法完成加载时子类才会尝试加载。此机制的好处是:加载rt.jar时不管是哪个加载器加载,都会委托给BootStrap Classloader,保证使用不同的类加载器也可以得到同一个结果?

浙公网安备 33010602011771号