JVM 垃圾回收机制( 一) 回收对象的判定
关于JVM 的垃圾回收机制,我们一般都没过多深入,因为JAVA 和 C++ 的一个很大区别就是,JAVA 帮我们做了垃圾回收,而不用像C++ 那么样手动进行回收,当然任何自动的东西都存在一定弊端,比如机器人,即使自动程度很高,但是在处理某些感情问题上,肯定处理上就会有遗漏,开个玩笑啦, 下面我们先来了解一下JVM 的垃圾回收是怎么回事。
一、如何判断对象已经死亡
JVM 会回收那些不在使用的对象,或者说是已经死亡的对象,从而达到节省空间的目的,那么我们肯定的判断哪些对象已经死了,不在使用呢?
1 引用计数算法:
这算法原理很简单,就是当我们的对象没引用的时候,有一个计数器,比如count,就会count
++,同理,如果被应用的对象设为null,那么count --,直到 count = 0的为止。当JVM
进行回收的时候,那么他会找到这些count = 0 的对象,默认没有被使用,就进行回收了。
这个算法,理论上是挺好的,但是当对象相互引用的时候就无法进行了,举个例子:比如A 类,里面有个B类的引用
b,同时B类里面有个A类的引用a,当我们同时A a= new A(),B b = new B();这时候是一个强引用,都会count
++,当我们让里面的引用a.b =b,b.a=a;的时候就是第二次引用,count 都变成了2,如果这时让
a =null,b =null,count -- ,当我们回收的时候发现count = 1;JVM 就不会回收了,那么就会浪费内存,这也是引用计数算法的主要劣势,这里也顺便分析下这种算法:
1. 需要单独的字段存储计数器,增加了存储空间的开销;
2. 每次赋值都需要更新计数器,增加了时间开销;
3. 垃圾对象便于辨识,只要计数器为0,就可作为垃圾回收;
4. 及时回收垃圾,没有延迟性;
5. 不能解决循环引用的问题;
2 可达性分析算法
这种算
法可以对象循环引用的问题,基本原理是:通过一个叫“GC
ROOT”根对象作为起点,然后向下节点搜索,搜索路径叫引用链,也就是我们常说的引用,当我们从ROOT
找不到任何一条路径相连的对象的情况下,就可以判定可以回收了,相当于这对象找不到家的感觉,这里引用JVM的图:
2 .1 GC ROOT 回收对象的范围包括:
a. 虚拟机栈(栈帧中的本地变量表)中引用的对象
b. 方法区中类静态属性引用的对象
c. 方法区中常量引用的对象
d. 本地方法栈中JNI(native方法)引用的对象
关于一些堆栈 方法区的分布作用,以后再讲,可以先参考:
http://www.360doc.com/content/11/0504/12/3903749_114271703.shtml
虽然有可达性分析算法来判定对对象状态,但这并不是对象是否被回收的条件,对象回收的条件远远比这个复杂,比如无法通过ROOT找到的对象,也不一定会回
收,会进入一个死缓的阶段,那些无法通过根节点
引用链找到的对象,会被第一次标记,并进行一次筛选,筛选条件是此对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方
法,或者finalize() 方法已经被虚拟机调用过,虚拟机都视为“没必要执行”。
如果该对象被判定为有必要执行finalize(),那么对象会被放置在一个F-Queue
的队列中,并由一个优先级较低的Finalizer 线程去执行,这里的执行是 JVM
会触发这个方法,但并不保证等待他运行结束,因为finalize() 方法执行慢,或者死循环,会影响该队列其他元素执行。
执行finalize() 方法就会进行第二次标记,然后等待JVM 进行回收了,而在finalize() 方法执行的同时,可以对对象进行“拯救”,也就是说在执行方法内部,再次对对象进行引用,那么对象就复活了,看代码:
- package com;
- import java.lang.reflect.Method;
- import org.springframework.cglib.proxy.MethodInterceptor;
- import org.springframework.cglib.proxy.MethodProxy;
- public class FinalizeGC{
- public static FinalizeGC save_gc = null;
- public static void main(String[] args) throws InterruptedException {
- save_gc = new FinalizeGC();
- // 断掉引用链
- save_gc = null;
- // 调用finalize 回收,里面进行了 拯救 行动
- System.gc();
- // finalize 优先级比较低,暂停0.5秒等待他执行
- Thread.sleep(500);
- System.out.println("该对象状态是--->"+save_gc);
- // 这里代码同上,但是已经拯救无效
- save_gc = null;
- System.gc();
- Thread.sleep(500);
- System.out.println("该对象状态是--->"+save_gc);
- }
- // 重写该方法
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- System.out.println("正在执行 finalize 方法");
- // 从新引用
- FinalizeGC.save_gc = this;
- }
- }
- 结果:
- 正在执行 finalize 方法
- 该对象状态是--->com.FinalizeGC@c17164
- 该对象状态是--->null
可以看出,finalize
在GC的时候已经执行了,并且对象已经被拯救了,但是发现只被执行了一次,也就只能被拯救一次,因此有一个有值,有一个是null.这里可以看出JVM
对对象的finalize()只会被执行一次,这里仅仅做了解,不建议重写该方法,因为这样会干扰对象的回收调用机制,而且运行代价很高。
除了上述那些对象以外,还有一些废弃常量的回收,比如:有一个一个字符串"ABC" 已经进入常量池中,但是当前系统没有任何地方引用该对象,该常量就会被清除常量池。
同时还有一些废弃的类,或者无用的类也会被回收,这里一些判定条件有:
a.该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例
b.加载该类的ClassLoader 已经被回收
c.该类的java.lang.Class 对象在没有任何地方呗引用,无法在任何地方通过反射访问该类的方法。
小结:
1.这里仅描述了一些JAVA 对象是否可以回收的一些判定方法和条件
2.关于还有垃圾收集的一些算法以及垃圾回收器,这些才是描述JVM 如何整理这些分布在内存中的过期对象,如何进行批量的手机 删除工作的,这个以后再解释吧。
JVM 垃圾回收机制( 一) 回收对象的判定的更多相关文章
- 2.1.JVM的垃圾回收机制,判断对象是否死亡
因为热爱,所以坚持. 文章下方有本文参考电子书和视频的下载地址哦~ 这节我们主要讲垃圾收集的一些基本概念,先了解垃圾收集是什么.然后触发条件是什么.最后虚拟机如何判断对象是否死亡. 一.前言 我们 ...
- Qt ------ 内存回收机制、new对象的回收
写在前面的总结: 建议:对于不能指定父对象的对象(对象通过moveToThread()移入其他线程.没有继承QObject的类产生的对象),在其他线程通过deleteLater()内存回收,其他通过指 ...
- java中垃圾回收机制和引用类型
在java中JDK1.2版本以后,对象的引用类型分为四种,从高到低依次为:强引用.软引用.弱引用.虚引用. ①强引用的特点:垃圾回收机制绝不会回收它,即使内存不足时,JVM宁愿抛出OutOfMemor ...
- Java jvm 内存回收机制
http://blog.csdn.net/yaerfeng/article/details/51291903 在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方 ...
- Java基础知识总结之垃圾回收机制
垃圾回收机制 Java垃圾回收机制是Java语言的重要功能之一.当程序创建对象,数组等引用类型对象时,系统会自动在内存区为之分配一块内存,对象就保存在这块内存区内,当这块内存不再被任何变量引用时,这块 ...
- Java_垃圾回收机制(未掌握)
垃圾回收机制 任何一种垃圾回收算法一般要做两件基本事情: 发现无用的对象(没有任何变量引用该对象) 回收无用对象占用的内存空间 垃圾回收相关算法: 引用计数法, 引用可达法 分代垃圾回收机制: 不同的 ...
- Java基础教程——垃圾回收机制
垃圾回收机制 Garbage Collection,GC 垃圾回收是Java的重要功能之一. |--堆内存:垃圾回收机制只回收堆内存中对象,不回收数据库连接.IO等物理资源. |--失去使用价值,即为 ...
- java垃圾回收机制学习总结
最近学习了一下java垃圾回收机制,将其主要内容大致总结一下: 1.什么是垃圾回收机制 java GC机制(garbage collection,垃圾收集,垃圾回收),是java特有的机制,作为jav ...
- JVM内存回收机制简述
JVM内存回收机制涉及的知识点太多了,了解越多越迷糊,汗一个,这里仅简单做个笔记,主要参考<深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)> 目前java的jdk默认虚拟机为H ...
随机推荐
- SQL:deferrable initially deferred
SQL> create table cust(id number,name varchar2(10));Table created SQL> alter table cust add co ...
- CentOS6.5 --安装orale 11g(上)
Linux内核版本:Linux version 2.6.32-431.23.3.el6.x86_64 (1) 在Windows上安装Xmanager Enterprise 4工具,该工具是用来 ...
- 高逼格的实现WiFi共享,不安装第三方wifi共享软件,两种方式实现开启wifi的功能
作为一枚程序员,不会点高逼格的doc命令,那么都有点感觉对不起自己的行业了,好了废话就到这里了 第一种方式: 首先使用cmd命令:window键+R 然后输入cmd回车 第一种方式: 第一步: 设 ...
- SSH连接LINUX乱码解决方法
1.vi /etc/sysconfig/i18n 将内容改为 LANG="zh_CN.GB18030" LANGUAGE="zh_CN.GB18030:zh_CN.GB2 ...
- linux中运行python
1.在终端中输入: python **.py 2.最爽的方法: emacs中配置python运行环境.
- C++程序设计实践指导1.12数组中数据线性变换改写要求实现
改写要求1:分别用指针pa.pb代替数组 改写要求2:从键盘输入data元素 元素个数任意,输入0结束 #include <cstdlib> #include <iostream&g ...
- Java程序的成长之路
转载链接:http://www.admin10000.com/document/2901.html 互联网发展日新月异,社会科技每天都在发生着翻天覆地的变化,而程序员已经成了这个时代的庞大群体,各种各 ...
- Tomcat学习笔记 - 错误日志 - Tomcat安装版安装后第二次启动后闪退(转)-- javac不是内部或外部命令 -- 配置java环境教程
如果安装成功并且安装完成第一次启动是成功的,第二次就闪退的话,原因之一是没有配置java的环境.在网上找的配制方法有很多错误,测试javac命令时候会提示不是内部或外部命令,找到一个正确的教程.如下, ...
- C# 导出Excel Aspose.Cells
public void ExportExcel() { Workbook workbook = new Workbook(); //工作簿 workbook.Worksheets.Clear(); w ...
- html简单定位
(1) 两个块水平排列 将两个块都设为浮动即可.注意不能将两个块的position属性设为absolute(绝对定位) #div1{ background-color: red; float:left ...