因为程序计数器,栈,都是随着线程的开启而开启,随着线程的消失而销毁,所以这部分基本不需要垃圾回收器来操心,剩下的就是堆和方法区则不一样,每个接口的实现类内存都不一样,所以程序在运行期间的内存分配是动态的
怎么判断堆里面的对象是死的还是活的?
-
引用计数算法
给一个对象添加引用计数器,每当一个地方引用它,则+1,当引用失效后,则-1,如果这个对象的引用是0,则就证明没有被使用(java 虚拟机没有采用这个,因为这个没法判断对象之间循环引用的问题) -
可达性分析算法(c ,java 常规采用的)
-
再谈引用
1、强引用(永远不会回收 new出来的)
2、软引用(如果发生内存泄露之前就会回收 softReference 类)
3、弱引用(下一次垃圾回收器收集之前,无论是否内存足够,都会被回收,weakRefrencen类)
4、虚引用 (最弱的,唯一的作用就是能在这个对象被收集器回收的时候收到一个系统通知 phantomReference) -
判断死亡(两步走)
1、可达性分析算法之后 先标记一次
2、加入f-queue队列一次
垃圾收集算法
-
标记-清除算法
分为两个阶段,标记和清除
不足:
1、效率太低(标记和清除的效率都不高)
2、片段不连续,清楚之后有大量的内存碎片,当有大内存的对象需要大内存时,导致不能找到; -
复制算法
1、为了解决效率问题,复制算法出现了
2、他可解决内存碎片的问题,只是他的代价是将内存缩小为原来的一半
3、现在的商业的虚拟机都是采用这种算法回收新生代
4、当对象的创建和销毁频繁时,效率就会很低
5、如果想使用100%的空间,必须要有额外空间作为辅助(因为每次都是使用一半然后进行复) -
标记-整理算法
1、和标记清除一样,只是在第二阶段不是清除,而是先整理,然后直接清除掉边界以外的内存 -
分代收集算法
1、当前商业虚拟机的垃圾收集都采用分代收集
2、根据对象的存活时间将内存分为几块
eg:一般将java堆分为新生代和老生代,这样就可以根据不同代之间选择不同的收集算法,新生代中,每次垃圾收集时都会发现大量的对象死去,所以选用复制算法,在老生代中,因为对象存活性高,没有额外的空间,对他进行分配担保,就必须使用标记清理或者标记整理算法进行回收
hotSpot的算法实现
- 枚举根节点
- 安全点
- 安全区域
垃圾收集器
- serial收集器
- parNew收集器
- parallel Scavenge收集器
- serial old收集器
- parallel old收集器
- cms收集器
- G1收集器
内存分配和回收策略
- 对象优先在eden分配
- 大对象直接进入老年代
- 长期存活的对象将进入老年代
- 动态对象年龄判定
- 空间分配担保
网友评论