CLass加载过程:
loading:加载
加载阶段使用的是双亲委派:1、有缓存提高效率;2、处于安全考虑
class加载会先查询缓存(一个list或者map),缓存没有才会查询下一个加载器。缓存中有的话就不进行下一步。
为什么使用双亲委派?
1、避免重复加载,因为父亲已经加载过了,没有必要儿子再加载一遍。
2、处于安全考虑:如果随意定义的的类型随意替代java核心的API会存在安全隐患,在加载自定义的加载器的时候首先会寻找APP,APP中没有那么会向上寻找,这个就是类加载器的未派机制。
类是如果加载的
有一个defineClass方法加载class文件,defineClass(name,bytes,0,bytes.length);
class的name 字节数组:转化为那一部分的内存,起始的位置,结束的位置。通过这个方法转化为class对象;
linking:连接
Verification:验证
校验文件是否符合jvm的规定。
preparation:准备
给静态成员变量赋默认值;在initialized的时候进行初始化。
Resolution:解析
将类、方法、属性等符号引用解析为直接引用。
initialize:初始化
1、给preparetion的静态成员变量赋初始值。
JMM
缓存行:读取缓存的时候会读取一整行的数据,目前一般都是64bytes
伪共享:统一缓存行的两个不同数据,被两个不同的CPU锁定。产生互相影响。解决:缓存行对齐
乱序问题
CPU为了提高指令执行效率,在一条指令执行的过程中,去执行另一条指令,前提是:两条指令没有依赖关系。
如何保证有序性
CPU加内存屏障:两条指令不能重排
1、对象创建的过程
1、loading 、linking 、 initializing
2、申请内存
3、成员变量赋默认值
4、执行构造方法:成员变量顺序赋初始值、执行构造方法语句
2、对象在内存中的存储布局
普通数据
1、markWprd
2、classPoint :指向class
3、instance :实例数据
4、padding:对齐
数组
1、markWord
2、classpoint
3、数组大小 4
4、数组内容
5、padding
3、对象头具体包含什么(markWord)64位
1、锁标志位
2、GC
参考:马士兵笔记四
GC
没有引用指向的一个或者一堆对象叫做垃圾
如何定位垃圾
如何找到了垃圾有两种算法
refrence count :引用计数
引用指向引用对象,当引用对象的引用没有的时候就是垃圾
他无法解决循环引用:A 引用 B B引用 C C引用 A 但是没有一个指向引用指向这三个
Root searching:根可达算法
跟对象:线程栈变量 、 静态变量 、 常量池 、JIN (引用的C 或者C++)
也就是说程序运行起来马上应用到的对象就叫做根对象
GC常用算法
Mark-sweep 标记清除
把没有用的对象标记处之后清除。
适用于存活对象比较多的情况下效率比较高
需要扫描两遍(第一遍寻找出有用的对象,第二遍寻找出可回收的对象),效率偏低,容易产生碎片
Copying 拷贝
内存一分为二,把有用的拷贝,没用的清除。
对象需要移动和复制的。
适用于存活对象较少的情况,只扫描一次,没有碎片。
Mark-compact 标记压缩
把可用对象移动到一个地方其他的直接回收
扫描两次需要移动复制对象。
JVM分代模型