JVM之垃圾回收
来源:互联网 发布:淘宝送装入户 编辑:程序博客网 时间:2024/06/05 00:57
GC需要完成的3件事情
哪些内存需要回收?
在隔离区的程序计数器、虚拟机栈、本地方法栈三个区域随着线程而生而灭。每一个栈帧中分配多少内存基本上都是固定已知的,因此这几个区域的内存分配和回收具有确定性,就不多考虑内存回收的问题了,在方法或线程结束的时候就自然回收了这部分的内存。在java堆和方法区中,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间才能知道会创建那些对象,这部分内存的分配和回收是动态的,GC所关注的就是这部分内存。
什么时候回收?
回收第一件事要搞明白就是,在堆中,哪些对象时“存活”的,哪些“死去”的不再被任何途径使用的对象。两种存活判断方法:引用计数算法、可达性分析算法;
引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被引用的。弊端:不能解决对象间相互循环引用的问题,所以java虚拟机不采用。
采用的一般有:微软的COM(Component Object Model)技术、使用ActionScript3的FlashPlayer、Python语言等进行内存管理。
可达性分析算法:通过一系列的称为“GC roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain,简称RC),当一个对象到GC Roots没有任何RC相连,证明此对象时不可用的。现在主流的商用语言(java、C#等)都是使用可达性分析算法。
在java语言中,可作为GC Roots的对象包含有
虚拟机栈中的引用对象;
方法区中类静态属性引用的对象;
方法区中常量引用的对象;
本地方法栈中JNI(即一般说的Native方法)引用的对象;
生存还是死亡?
即使在可达性分析算法中不可达的对象,也并非是必须被回收,可以缓一缓,对象可以进行一次自救。在垃圾回收清理内存之前先调用一次finalize()方法。
public class FinalizeEscapeGC { public static FinalizeEscapeGC SAVE_HOOK=null; public void isAlive(){ System.out.println("yes, i am still alive"); } @Override protected void finalize() throws Throwable{ super.finalize(); System.out.println("finalize method executed!"); //对象重新建立 GC root 连接链 FinalizeEscapeGC.SAVE_HOOK=this; } public static void main(String[] args) throws Throwable{ SAVE_HOOK = new FinalizeEscapeGC(); //对象第一一次成功拯救自己; SAVE_HOOK =null; System.gc(); //因为fianlize方法优先级很低,所以暂停0.5秒等待他 Thread.sleep(500); if(SAVE_HOOK!=null){ SAVE_HOOK.isAlive(); }else{ System.out.println("no,i am dead :("); } //下面这段代码与上面的完全相同,但是这次自救却失败了;-------------------finalize方法只会被调用一次; SAVE_HOOK =null; System.gc(); //因为fianlize方法优先级很低,所以暂停0.5秒等待他 Thread.sleep(500); if(SAVE_HOOK!=null){ SAVE_HOOK.isAlive(); }else{ System.out.println("no,i am dead :("); } } }
对象自救描述:
1、判断是否存在对象与GC Root的reference chain:
如果引用链存在:回收内存;
2、如果不存在:第一次进行标记,并且进行筛选(筛选条件:是否有必要执行finalize()):
没必要执行:当对象没有覆盖finalize()或finalize()方法已经被调用过一次,回收内存;
3、有必要执行:将对象放到F-Queue的队列中,自动创建线程finalizer,第二次小规模标记;
finalize()未执行完,自救失败:回收内存
4、建立引用链,自救成功:不回收
如何回收?
垃圾收集算法
标记-清除算法(mark-Sweep)不足:两个过程,效率不高;
清除之后会产生大量不连续空间碎片,从而导致在程序运行时,无法找到足够连续内存,不容易给大对象分配空间,而出发另一次垃圾收集动作。
标记-清除算法是算法的基础,因为这个算法有以上不足,以下算法都是针对这些特点进行修改和优化。
复制算法(copying)
不足:对象存活率较高时,频繁进行复制操作,效率变低;如果不想浪费50%的空间,就必须额外的空间进行分配担保;
标记-整理算法(Mark-Compact)
和标记-清理算法标记过程相同,但不会直接清理掉对象,让所有存活的对象向一端移动,直接清理掉端边界外的内存。
分代收集算法
将java堆分为新生代和老年代,新生代根据其特点,使用复制算法,只需付出少量存活对象复制的成本,而老年代特点是对象存活率时间长,没有额外空间做担保,只能选择标记-清理或标记整理
- JVM 之垃圾回收
- JVM之垃圾回收
- JVM之垃圾回收
- jvm之垃圾回收
- JVM之垃圾回收
- 透视JVM之垃圾回收
- jvm之垃圾回收器
- 透视JVM之垃圾回收
- JVM垃圾回收 之 G1
- JVM之垃圾回收算法
- JVM垃圾回收之我见
- JVM垃圾回收之finalize
- JVM之垃圾回收器
- 读书笔记之JVM垃圾回收
- jvm之垃圾回收算法
- 《java performance》读书笔记之 jvm 垃圾回收
- JVM原理之垃圾回收机制
- JVM之——垃圾回收简介
- UVA
- 022-Java-013
- 集算器如何将第一个sql语句中的结果作为第二个sql的参数值
- 5-6.枚举enum练习。
- 21.java语言基础-三元运算符
- JVM之垃圾回收
- 冒泡排序
- Android
- 报错The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
- 22.java语言基础-分页业务逻辑算法
- 编辑距离 dp
- 正则表达式
- WPF多线程UI更新——两种方法
- Exception:No Session found for current thread