java程序在运行之前需要将class文件编译成.class文件(二进制字节码文件),运行的时候,jvm就会读取相应的class文件,并且解析出内容,在内存中构造出类对象并进行初始化.
类对象是干什么的了,简单来讲他是描述了一个类具体长什么样子的;具体来说他描述了这个类有哪些属性(名字,类型,权限修饰符),有哪些方法(名字,参数类型与个数,返回值);同时还描述了这个类继承了哪个类,实现了哪一些接口等,类对象也是创建实例的基本工具;
加载:找到.class文件,读取文件内容,并且按照.class文件的方式解析.
验证:检查.class文件的内容是否符合要求.
准备阶段:主要做的是静态变量的内存分配.
解析:初始化字符串常量,将符号引用替换为直接应用.
初始化:针对类进行初始化,初始化静态成员,执行静态代码块,加载父类…
对于什么时候类加载的这个问题,统一的回答是什么时候用什么时候加载,类似于懒汉模式.并且只加载一次.
- 创建这个类的实例的时候.
- 使用这个类的静态实例,静态方法
- 使用了这个类的子类(加载子类会触发类的加载,参照1.2)
要了解双亲委派模型,我么首先去了解什么是类加载器,以及有什么类加载器.
类加载就是JVM加载类,是有ClassLoader这样的模块来组成.
Jvm带了多个类加载器,我们也可以自己去实现类加载器.
- BootStrap :负责加载标准库中的类
- Extension :负责加载JVM扩展的类,及时java语言规范里面没有写出来的,但是jvm已经实现了的.
- Application:负责加载咋们项目里面的类加载器.
而什么是双亲委派模型了,就是描述上述类加载器的协作过程,就是双亲委派模型.
具体协作过程:
- 那么上述三个类加载器存在父子关系.
- 首先会从Application这一级进行加载,但是Application不会一上来就访问自己锁管理的目录,而是委派给父亲,同理,extension也会重复相同的行为,直至没有父亲位置,看到这里如果对一种思想明白的同学可能就会顿悟了,这不就是个类似递归的流程吗,可以这么说,但也不是完全类似的,递归是一层层递进,然后一层层返回的,也就是说他会回到最开始递归的函数中去,二双亲委派模型这里如果最顶层的Bootstrap找到了相对应的全限定类名,那么就不会再回来了,如果没有找到,才会继续交给儿子去处理,如果最终都没有找到,就会抛出异常了.
简单来说哟,程序员只需要申请内存,释放内存的操作交给Jvm去执行,jvm会自动对当前内存进行判断,是否需要释放,并自动进行释放.但是这个方案的使用也会造成额外的空间加时间的消耗.空间上会消耗cpu和内存资源,在空间上,GC有个最大的问题.
STW问题:反应在用户这里就是明显的卡顿.但是一般认为程序的开发效率>运行效率.所以GC垃圾回收机制任然适用.
要了解这个问题,我么首先的去知道JVM内存区域分为什么部分;
- 程序计数器:这一块区域是固定的内存空间,不必回收.
- 栈:释放实际确定,不必回收.
- 方法区:类对象,加载之后也不需要回收.
所以可以看出来,GC主要释放的堆上的对象.
GC回收的最小单元是对象.对于堆上的内存回收策略是:
也就是说,只用完全不会使用的对象,GC才会回收相应的内存空间.
如果一个对象不再使用了,就说明是垃圾了,在Java中,需要凭借引用.假设一个对象没有任何的引用能够指向他了,这个对象自认也就不会被使用了.举个简单的例子,对象的引用就好像是钥匙.堆区的对象就好像是房子,没有了钥匙,自然房子也就不能是用来了,就需要物业给回收掉(当时也完全可以把锁个撬了).
最关键的要点就是:通过对象的引用来判断当前对象是否被使用了.没有引用了就视为无法被使用了
那么怎么判断一个对象是否有引用了:
引用计数(python,php):给每个对象都加上一个 计数器,表示当前这个对象有多少个引用;客观分析:优势:实现简单,执行效率高;缺点:空间利用率低;可能出现循环引用.
可达性分析(java):约定一些变量,称为GC ROOTS;每隔一段时间,从GC ROOTS 开始遍历,看看当前变量是否能够访问到;能被访问到就是可达的,反之不可达的.
- 栈上的变量;
- 常量池应用的对象;
- 方法区:应用类型的变量;
1.标记清除
标记处垃圾之后,直接把对象对应的内存空间回收了;优点:简单粗暴;缺点:会导致内存碎片,从而导致空间利用率低;
2.复制算法
依靠另一块与原空间相同大小的空间,在回收的时候,将原空间中的"非垃圾"对象复制到另一侧空间,然后将原空间整体释放,这样就解决了内存碎片问题;缺点:这样的空间利用率更低,因为用一半内存,另一半只起到了一个复制的作用.
3.标记整理
熟悉熟悉表删除操作理解起来非常简单;是一个搬运的过程;优点;相对于标记清除来说,它解决了内存空间问题,相对于复制算法来说,它解决了空间利用率低的问题,但是他的操作比较耗时;
4.分代回收
在前三种的回收算法上,感觉都差点意思,那么JVM采用的分代回收,就很好的整合了后两种算法;上图:
其中,在新生代执行的算法是复制算法,在老年代的回收算法是标记整理算法.
以上的都是理论,JVM具体有很多的垃圾回收器,比如CMS,G1,ZGC,学友余力之时在做进一步的了解吧.