JAVA程序运行流程
JVM数据区组成
会发生内存泄漏: 虚拟机栈、本地方法栈、堆
堆内存异常
不断的New对象,当最后一个对象创建后,无法为其分配内存空间
栈内存异常
不断有变量创建,造成栈内存满
垃圾回收机制
一、首先判断清理哪些内容
垃圾回收前要判断一个对象是否存活,哪些死去。
引用计数器算法(Python):
给每个对象添加一个计数器,当有一个引用时,计数器+1,引用失效,计数器-1。为0时,说明没有引用。但是没办法解决对象之间循环引用。
可达性分析算法(JVM):
通过一个称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链。当 GC Roots 到这个对象不可达时,证明该对象不可用,可以被清理。
可作为GC Roots 的对象包括下面几类:
- 虚拟机栈中引用的对象,(局部变量)
- 本地方法栈(JNI)引用的对象
- 方法区中的一些常量引用的对象
四种引用:![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/639a1fdc2ca652b967124d7bc0c99001.png)
二、其次怎么清理
标记清除算法
根据可达性分析算法得出哪些对象可以被回收,然后进行标记清除。
缺点:
1、这样清理后,在内存中会有很多零散的内存碎片,浪费内存
2、标记清除的效率并不高
标记整理算法
同样对可回收的对象进行标记后,进行分区整理,然后统一回收。
复制算法
在内存中会复制一份容量相同大小的内存区域,当要回收时,将存活的对象依次存入预留区,然后清空之前存放区的对象,并将之前的存放区–>预留区。
缺点:很明显解决了之前内存不足的问题,并且效率也高。但是会额外占用一块空闲区,空间利用率很低。如1G的内存只有512M可用。
分代垃圾回收算法
分代垃圾回收算法其实就是对内存回收做了分区,并结合了上面的算法。
-
年轻代
。Eden(伊甸)区
。Survivor(存活)区
--from区 --to区 结合了复制算法,一个作为存储区,一个作为预留区。
在Eden区中经过可达性算法得到存活的对象,存入Survivor区,并且记录对象被引用的次数,然后清空Eden区。当记录的引用次数超过15次时,转入老年代。
Survivor区中的对象失效后,会将from区中存活的对象利用复制算法放到to区中。
-
老年代
存储存活率较高的内存对象。
老年代中的对象存活率高,所以直接采用标记清除算法、标记整理算法进行清除。
当新生代中内存不够时,直接转为进入老年代。
当老年代中内存不够时,直接full GC (回收整个堆的内存垃圾),会停止所有工作的线程。