类加载过程:
1.加载:通过类加载器,将class文加加载到内存。
2.验证:验证文件是否符合java规范。
3.准备:就是为static修饰的变量,赋予初始值,并且分配内存空间。
4.解析:就是将java代码中的符号引用替换为直接引用。
5.初始化:对变量赋值。
jvm运行时数据区组成:
方法区(1.8之后叫元空间):主要存放类信息,和static的变量,线程共享。
堆:对象和数组存放的地方,分为新生代和老年代,线程共享。
栈:存放栈帧,每一个栈帧都是线程独享的。
本地方法栈:存放一些c语言的方法。
程序计数器:就是记录线程执行到哪一个地方。线程独享。
双亲委派机制:
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。(防止重复加载。)
这是为了安全着想,保证按照优先级加载.如果用户自己编写一个名为java.lang.Object的类,放到自己的Classpath中,没有这种优先级保证,应用程序类加载器就把这个当做Object加载到了内存中,从而会引发一片混乱.而凭借这种双亲委派机制,先一路向上委托,启动类加载器去找的时候,就把正确的Object加载到了内存中,后面再加载自行编写的Object的时候,是不会加载运行的.(防止自己写的类和java自带的类冲突)
如何判断一个对象已经死亡:
1.引用计数算法:就是当没有任何地方引用这个对象的时候,就说明对象已经死了。但是无法避免对象之间相互引用。
2.可达性分析算法:从GC Roots,垃圾回收起点,没有任何引用链到达这个对象的时候,就说明这个对象已经死了。
常用的垃圾回收算法(堆):
1.标记-清除算法:先标记需要清楚的对象,标记完成后进行回收,缺点是会产生大量的碎片空间。
2.复制算法:将内存一分为二,当一块用完后,将存活的对象复制到另一块,对最开始的一块进行清楚。缺点:空间利用率低。
3.标记整理算法:先对可用的对象进行标记,然后将可用的对象移动到一段连续的区域,清楚其他区域。
JVM优化:
暂时搞不懂,我就知道少创建死循环,递归不要太深会造成栈溢出。