虚拟机
1 jvm 运行时数据区 ,公有 堆和方法区 私有 虚拟机栈,程序计数器,本地方法栈
其中堆用于存放对象 方法区 存类的信息 常量池,静态变量,即时编译代码
虚拟机栈用于存放栈帧 ,每个栈帧对应一个个被调用方法
栈帧中 有局部变量表,操作数栈,常量引用,返回地址等
本地方法栈 允许线程调用操作系统本地方法
程序计数器 记录当前线程所执行的字节码的行号(指令位置)实现程序的逻辑控制
2 堆内存的分配 新生代young 和老年代perm 新生代分为eden区和两个survivor区
Eden和Survivor默认比例 8:1 由 -XX:SurvivorRation设置
Perm 区(持久代老年代)存放类class信息,常量池以及一些从新生代移动过来的对象(
不要滥用动态加载(反射),一个是造成Perm的不稳定,另一个是它的效率肯定没有new高,因为它需要先去通过符号向量寻找是否存在,不存在再加载,然后再通过newInstance实例化一个或多个实例)
新生代 存放朝生夕死的对象 使用复制算法minorGC 老对象会被存入持久代
3 内存溢出问题 以及参数设置 ???
4 回收算法 和回收器
引用计数 和根搜索(可达性分析)实现对象的存活状态判断
一个对象至少要被标记两次才会真正的去销毁 且记住finalize()只执行一次
回收方法区:废弃常量和无效类
标记清除 大量的碎片 标记整理 让存活对象全部往一端移动 然后清理另一边。
默认使用分代收集,新生代对象死亡频繁使用复制老年代存活高不建议复制所以用标记清理或标记整理。
几种收集器 serial parallel cms据实际应用需求、实现方式选择最优的收集方式才能获取最好的性能。
5 字节码 平台无关性 包含魔数 版本号 常量池(引用) 访问标志,类接口索引集合,字段集合,方法表集合 属性集合
6 类加载过程 加载 验证准备解析(合为连接) 初始化 使用 卸载 但是执行完毕的不固定,所以可能存在加载分配了地址 但是 对象并没有实际初始化 为null(类加载的指令重排导致 单例安全问题,引用逃逸问题)
7类要初始化的情况 使用new创建对象,使用类的静态字段 反射调用 子类触发父类初始化 虚拟机初始化主类 这些都是主动引用 (即需要返回一个类) 这些都会导致类加载
而使用类中常量, 定义数组时引用了类不会引起类初始化
以及用子类调用父类的静态字段,子类并不会初始化 只有父类会
类加载执行顺序为 父静态 子静态 父非静 父构 子非静态 子构造
其中静态只会在第一次加载类是执行
8 类加载器 获取类文件二进制流放入虚拟机 双亲委托机制
Bootstrap extension application 三个 以及自定加载器
阐述tomcat的类加载机制
9 方法的调用
栈帧实现方法调用 方法的入口 也就是由哪个对象执行 有两种方式 1 直接解析静态分派,如重载的方法,父类方法,私有方法静态方法,构造方法。(即非虚方法)这些方法执行时对象类型是确定。 而对于重写的方法等虚方法,在在运行时才确定类型(子类向上转型为父类 父类调用这些方法时要确认类型)属于动态分派
所以说java是静态类型语言 伪泛型 但是是动态语言。
10 字节码执行引擎
字节码 解释执行(直接解释字节码执行)和编译(翻译为机器码 例如c++就是)执行
JIT即时编译(以前的java都是解释执行的)
对热点代码(所以叫hotspot)进行编译将其转为机器码(所以效率高 执行越来越快) 实现混合模式执行
11 前端编译器将java文件编译为字节码 如javac 后端编译器 将字节码翻译为机器码 如Hotspot虚拟机 也有直接java编字节码的
Javac的过程 解析和填充符号表 注解处理 语义分析(检查,控制分析)和生成字节码
语法糖 即在前端编译时使用了 但编为字节码就统一了
包括Java伪泛型、变长参数、自动装箱拆箱、遍历循环,枚举,断言,lambda表达式等
关于泛型的桥方向 枚举的实质 lambda的应用
12编译优化技术
早期优化,即前端编译器的,如javac。使用语法糖等。
晚期(运行期)优化,即后端编译器JIT的优化,如公共子表达式消除,数组边界消除,方法内联(内联缓存),逃逸分析(栈上分配,同步消除,标量替换)等。
13 关于指令重排和优化 内存屏障和安全的问题1指令重排提高性能2通过插入特定类型的Memory Barrier来禁止特定类型的编译器重排序和处理器重排序,为上层提供一致的内存可见性保证。
内存屏障
保证特定操作的执行顺序。禁止指令重排
影响某些数据(或则是某条指令的执行结果)的内存可见性,强制缓存刷出,得到数据最新版本
14 内存模型JMM通过模型屏蔽系统和模型区别定义了多线程之间变量的可见性
JMM是共享内存模型。共享变量都在主内存(相当于虚拟机堆)线程私有的都在自己工作内存(相当于栈),在工作内存中对主内存的共享变量进行处理(所以有并发问题,线程不安全问题以及使用内存屏障来控制内存的访问来实现线程安全问题)
私有(本地)内存是抽象概念涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化
15 volatile的语义 1对所有线程的“可见性” (解释volatile i++为何不安全
) 使用前从主存获取最新值,修改后立即同步回主内存本来是要经过 cpu寄存器和ram之间的cpu缓存读写
2 禁止指令重排序优化 (线程安全的双重检查锁)确保该变量赋值操作的顺序不会重排 所以它是可见且有序的但是不是原子的(因为和其他范围的操作可能顺序重排了)
16 先行发生原则等