垃圾收集器与内存分配策略(1)
序言
Java和C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人想出来
GC(Garbage Collection)
学习目的
解决问题
- 内存溢出、泄漏
- GC成了性能瓶颈
GC区域
无关紧要的
与线程同生共死
分配内存时大致内存是确定的,方法或线程结束,内存自动回收,所以整个生命周期内存是比较确定的,没什么好说的。GC主要关注java堆(又称gc堆)
- 程序计数器
- 虚拟机栈
- 本地方法栈
至关重要的
Java堆
主要存放对象的 实例。
- 内存动态分配
- 内存动态回收
找垃圾算法
回收之前要确定对象是死是活(未来还会用到吗)
引用计数算法
有一个人引用计数就加1,少一个人引用计数就减1
优点
立即执行
计数为0就可以立即回收了
自我诊断
没必要再去new一个线程,是否可以回收自己就可以判断。
缺点
因为致命缺陷jvm不用这个
计数本身有一定的工作量
循环引用,形成永动
两个变量互相引用是无解(无法回收)的
根搜索算法
有一些特殊的对象可以作为gc root,从gc root出发,能到达之处就不是垃圾,不能到达之处就是垃圾
引用
上古时代的定义
- 存储着另一块内存的起始地址的变量
分类
强引用
Strong
- Object obj = new Object()
- 只要引用存在,就不会被回收
软引用
Soft
- 内存溢出之前会把软引用的对象回收,如果没用就报错了
- 通过SoftReference实现软引用
弱引用
Weak
- 比软引用更容易被回收
- 朝生暮死(下次回收开始弱引用必死)
- 通过WeakReference实现弱引用
虚引用
Phatom
- 唯一用处是对象被回收时能收到一个系统通知
- 通过PhatomReference实现虚引用
生存还是死亡
根搜索算法之后并未宣判死刑,对象仍有一线生机
两次标记
第一次标记
finalize方法
这个方法时java对c\c++程序员作出的妥协,这方法已经不适合这个版本了,应该被gc
对象自我救赎的最后一次机会
这个方法只可能被调用一次
第二次标记
- 如果对象救赎成功,就不会被标记,否则只有死路一条
回收方法区
回收废弃常量和无用的类
性价比低,可以不gc
垃圾收集算法
标记-清除算法
过程
标记
- 找垃圾算法
清除
缺点
- 效率不行
- 碎片太多,可能找不到大的连续的内存空间
地位
基石
- 之后的算法都是改进版
复制算法
过程
设置保留区,内存不够用时将所有活着的移到保留区,再清除
50%-50%会减少一半的可用内存,代价太大,而且也不需要如此。90%-10%又没法交换,所以一般是三部分:80%-10%-10%,只有一个10%是闲置的
分配担保
优势
- 简单易行
缺点
- 牺牲部分内存
- 对象比较多时复制操作会比较多
标记-整理算法
过程
标记
整理
- 把活着的拼接到一起
清除
分代收集算法
内存划分
新生代
- 新生代每次存活数量少,选复制算法
老生代
- 存活率高,使用标记-整理
