热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

JAVA基础:谈谈Java语言的垃圾收集器

JAVA基础:谈谈Java语言的垃圾收集器--Linux通用技术-Linux编程与内核信息,下面是详情阅读。
  垃圾收集器是Java语言区别于其他程序设计语言的一大特色。它把程序员从手工回收内存空间的繁重工作中解脱了出来。在SUN公司的Java程序员(Java Programmer)认证考试中,垃圾收集器是必考的内容,一般最多可以占总分值的6%左右。但是由于SUN公司的Java Programming Language SL-275 课程的标准教材中,对有关垃圾收集器的内容只做了非常简单的介绍,而另外的一些关于Java技术的书籍,比如《Java 2 核心技术》(Core Java 2)、《Java编程思想》(Thinking in Java)、《精通Java 2》等等,里面关于垃圾收集器的内容也几乎没有,或者只是简单地提两句,所以很多参加Java Programmer认证考试的中国考生,在垃圾收集器这一部分的得分都为0分(笔者曾认识一位SUN公司授权的中国Java培训班的老师,其考试总分为89%,但垃圾收集器的部分竟然也为0分)。鉴于此,笔者总结了这个垃圾收集器的专题,希望对广大Java技术的爱好者和准备认证考试的考生们有所帮助。
  我们知道,许多程序设计语言都允许在程序运行期动态地分配内存空间。分配内存的方式多种多样,取决于该种语言的语法结构。但不论是哪一种语言的内存分配方式,最后都要返回所分配的内存块的起始地址,即返回一个指针到内存块的首地址。
  当已经分配的内存空间不再需要时,换句话说当指向该内存块的句柄超出了使用范围的时候,该程序或其运行环境就应该回收该内存空间,以节省宝贵的内存资源。
  在C,C++或其他程序设计语言中,无论是对象还是动态配置的资源或内存,都必须由程序员自行声明产生和回收,否则其中的资源将消耗,造成资源的浪费甚至死机。但手工回收内存往往是一项复杂而艰巨的工作。因为要预先确定占用的内存空间是否应该被回收是非常困难的!如果一段程序不能回收内存空间,而且在程序运行时系统中又没有了可以分配的内存空间时,这段程序就只能崩溃。通常,我们把分配出去后,却无法回收的内存空间称为"内存渗漏体(Memory Leaks)"。
  以上这种程序设计的潜在危险性在Java这样以严谨、安全著称的语言中是不允许的。但是Java语言既不能限制程序员编写程序的自由性,又不能把声明对象的部分去除(否则就不是面向对象的程序语言了),那么最好的解决办法就是从Java程序语言本身的特性入手。于是,Java技术提供了一个系统级的线程(Thread),即垃圾收集器线程(Garbage Collection Thread),来跟踪每一块分配出去的内存空间,当Java 虚拟机(Java Virtual Machine)处于空闲循环时,垃圾收集器线程会自动检查每一快分配出去的内存空间,然后自动回收每一快可以回收的无用的内存块。
  垃圾收集器线程是一种低优先级的线程,在一个Java程序的生命周期中,它只有在内存空闲的时候才有机会运行。它有效地防止了内存渗漏体的出现,并极大可能地节省了宝贵的内存资源。但是,通过Java虚拟机来执行垃圾收集器的方案可以是多种多样的。
  下面介绍垃圾收集器的特点和它的执行机制:
  垃圾收集器系统有自己的一套方案来判断哪个内存块是应该被回收的,哪个是不符合要求暂不回收的。垃圾收集器在一个Java程序中的执行是自动的,不能强制执行,即使程序员能明确地判断出有一块内存已经无用了,是应该回收的,程序员也不能强制垃圾收集器回收该内存块。程序员唯一能做的就是通过调用System. gc 方法来"建议"执行垃圾收集器,但其是否可以执行,什么时候执行却都是不可知的。这也是垃圾收集器的最主要的缺点。当然相对于它给程序员带来的巨大方便性而言,这个缺点是瑕不掩瑜的。
  垃圾收集器的主要特点有:
  1.垃圾收集器的工作目标是回收已经无用的对象的内存空间,从而避免内存渗漏体的产生,节省内存资源,避免程序代码的崩溃。
  2.垃圾收集器判断一个对象的内存空间是否无用的标准是:如果该对象不能再被程序中任何一个"活动的部分"所引用,此时我们就说,该对象的内存空间已经无用。所谓"活动的部分",是指程序中某部分参与程序的调用,正在执行过程中,尚未执行完毕。
  3.垃圾收集器线程虽然是作为低优先级的线程运行,但在系统可用内存量过低的时候,它可能会突发地执行来挽救内存资源。当然其执行与否也是不可预知的。
  4.垃圾收集器不可以被强制执行,但程序员可以通过调用System. gc方法来建议执行垃圾收集器。
  5.不能保证一个无用的对象一定会被垃圾收集器收集,也不能保证垃圾收集器在一段Java语言代码中一定会执行。因此在程序执行过程中被分配出去的内存空间可能会一直保留到该程序执行完毕,除非该空间被重新分配或被其他方法回收。由此可见,完全彻底地根绝内存渗漏体的产生也是不可能的。但是请不要忘记,Java的垃圾收集器毕竟使程序员从手工回收内存空间的繁重工作中解脱了出来。设想一个程序员要用C或C++来编写一段10万行语句的代码,那么他一定会充分体会到Java的垃圾收集器的优点!
  6.同样没有办法预知在一组均符合垃圾收集器收集标准的对象中,哪一个会被首先收集。
  7.循环引用对象不会影响其被垃圾收集器收集。
  8.可以通过将对象的引用变量(reference variables,即句柄handles)初始化为null值,来暗示垃圾收集器来收集该对象。但此时,如果该对象连接有事件监听器(典型的AWT组件),那它还是不可以被收集。所以在设一个引用变量为null值之前,应注意该引用变量指向的对象是否被监听,若有,要首先除去监听器,然后才可以赋空值。
  9.每一个对象都有一个finalize( )方法,这个方法是从Object类继承来的。
  10.finalize( )方法用来回收内存以外的系统资源,就像是文件处理器和网络连接器。该方法的调用顺序和用来调用该方法的对象的创建顺序是无关的。换句话说,书写程序时该方法的顺序和方法的实际调用顺序是不相干的。请注意这只是finalize( )方法的特点。
  11.每个对象只能调用finalize( )方法一次。如果在finalize( )方法执行时产生异常(exception),则该对象仍可以被垃圾收集器收集。
  12.垃圾收集器跟踪每一个对象,收集那些不可到达的对象(即该对象没有被程序的任何"活的部分"所调用),回收其占有的内存空间。但在进行垃圾收集的时候,垃圾收集器会调用finalize( )方法,通过让其他对象知道它的存在,而使不可到达的对象再次"复苏"为可到达的对象。既然每个对象只能调用一次finalize( )方法,所以每个对象也只可能"复苏"一次。
  13.finalize( )方法可以明确地被调用,但它却不能进行垃圾收集。
  14.finalize( )方法可以被重载(overload),但只有具备初始的finalize( )方法特点的方法才可以被垃圾收集器调用。
  15.子类的finalize( )方法可以明确地调用父类的finalize( )方法,作为该子类对象的最后一次适当的操作。但Java编译器却不认为这是一次覆盖操作(overriding),所以也不会对其调用进行检查。
  16.当finalize( )方法尚未被调用时,System. runFinalization( )方法可以用来调用finalize( )方法,并实现相同的效果,对无用对象进行垃圾收集。
  17.当一个方法执行完毕,其中的局部变量就会超出使用范围,此时可以被当作垃圾收集,但以后每当该方法再次被调用时,其中的局部变量便会被重新创建。
  18.Java语言使用了一种"标记交换区的垃圾收集算法"。该算法会遍历程序中每一个对象的句柄,为被引用的对象做标记,然后回收尚未做标记的对象。所谓遍历可以简单地理解为"检查每一个"。
  19.Java语言允许程序员为任何方法添加finalize( )方法,该方法会在垃圾收集器交换回收对象之前被调用。但不要过分依赖该方法对系统资源进行回收和再利用,因为该方法调用后的执行结果是不可预知的。
  通过以上对垃圾收集器特点的了解,你应该可以明确垃圾收集器的作用,和垃圾收集器判断一块内存空间是否无用的标准。简单地说,当你为一个对象赋值为null并且重新定向了该对象的引用者,此时该对象就符合垃圾收集器的收集标准。
  判断一个对象是否符合垃圾收集器的收集标准,这是SUN公司程序员认证考试中垃圾收集器部分的重要考点(可以说,这是唯一的考点)。所以,考生在一段给定的代码中,应该能够判断出哪个对象符合垃圾收集器收集的标准,哪个不符合。下面结合几种认证考试中可能出现的题型来具体讲解:
  Object obj = new Object ( ) ;
  我们知道,obj为Object的一个句柄。当出现new关键字时,就给新建的对象分配内存空间,而obj的值就是新分配的内存空间的首地址,即该对象的值(请特别注意,对象的值和对象的内容是不同含义的两个概念:对象的值就是指其内存块的首地址,即对象的句柄;而对象的内容则是其具体的内存块)。此时如果有obj = null;则obj指向的内存块此时就无用了,因为下面再没有调用该变量了。
  请再看以下三种认证考试时可能出现的题型:
  
  程序段1:
  1.fobj = new Object ( ) ;
  2.fobj. Method ( ) ;
  3.fobj = new Object ( ) ;
  4.fobj. Method ( ) ;
  问:这段代码中,第几行的fobj 符合垃圾收集器的收集标准?
  答:第3行。因为第3行的fobj被赋了新值,产生了一个新的对象,即换了一块新的内存空间,也相当于为第1行中的fobj赋了null值。这种类型的题在认证0考试中是最简单的。
  程序段2:
  1.Object sobj = new Object ( ) ;
  2.Object sobj = null ;
  3.Object sobj = new Object ( ) ;
  4.sobj = new Object ( ) ;
  问:这段代码中,第几行的内存空间符合垃圾收集器的收集标准?
  答:第1行和第3行。因为第2行为sobj赋值为null,所以在此第1行的sobj符合垃圾收集器的收集标准。而第4行相当于为sobj赋值为null,所以在此第3行的sobj也符合垃圾收集器的收集标准。
  如果有一个对象的句柄a,且你把a作为某个构造器的参数,即new Constructor ( a )的时候,即使你给a赋值为null,a也不符合垃圾收集器的收集标准。直到由上面构造器构造的新对象被赋空值时,a才可以被垃圾收集器收集。
  程序段3:
  1.Object aobj = new Object ( ) ;
  2.Object bobj = new Object ( ) ;
  3.Object cobj = new Object ( ) ;
  4.aobj = bobj;
  5.aobj = cobj;
  6.cobj = null;
  7.aobj = null;
  问:这段代码中,第几行的内存空间符合垃圾收集器的收集标准?
  答:第7行。注意这类题型是认证考试中可能遇到的最难题型了。
  行1-3分别创建了Object类的三个对象:aobj,bobj,cobj
  行4:此时对象aobj的句柄指向bobj,所以该行的执行不能使aobj符合垃圾收集器的收集标准。
  行5:此时对象aobj的句柄指向cobj,所以该行的执行不能使aobj符合垃圾收集器的收集标准。
  行6:此时仍没有任何一个对象符合垃圾收集器的收集标准。
  行7:对象cobj符合了垃圾收集器的收集标准,因为cobj的句柄指向单一的地址空间。在第6行的时候,cobj已经被赋值为null,但由cobj同时还指向了aobj(第5行),所以此时cobj并不符合垃圾收集器的收集标准。而在第7行,aobj所指向的地址空间也被赋予了空值null,这就说明了,由cobj所指向的地址空间已经被完全地赋予了空值。所以此时cobj最终符合了垃圾收集器的收集标准。但对于aobj和bobj,仍然无法判断其是否符合收集标准。
  总之,在Java语言中,判断一块内存空间是否符合垃圾收集器收集标准的标准只有两个:
  1.给对象赋予了空值null,以下再没有调用过。
  2.给对象赋予了新值,既重新分配了内存空间。
  最后再次提醒一下,一块内存空间符合了垃圾收集器的收集标准,并不意味着这块内存空间就一定会被垃圾收集器收集。
推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 生成对抗式网络GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN介绍
    一、GAN原理介绍学习GAN的第一篇论文当然由是IanGoodfellow于2014年发表的GenerativeAdversarialNetworks(论文下载链接arxiv:[h ... [详细]
  • 无线认证设置故障排除方法及注意事项
    本文介绍了解决无线认证设置故障的方法和注意事项,包括检查无线路由器工作状态、关闭手机休眠状态下的网络设置、重启路由器、更改认证类型、恢复出厂设置和手机网络设置等。通过这些方法,可以解决无线认证设置可能出现的问题,确保无线网络正常连接和上网。同时,还提供了一些注意事项,以便用户在进行无线认证设置时能够正确操作。 ... [详细]
  • 本文详细介绍了相机防抖的设置方法和使用技巧,包括索尼防抖设置、VR和Stabilizer档位的选择、机身菜单设置等。同时解释了相机防抖的原理,包括电子防抖和光学防抖的区别,以及它们对画质细节的影响。此外,还提到了一些运动相机的防抖方法,如大疆的Osmo Action的Rock Steady技术。通过本文,你将更好地理解相机防抖的重要性和使用技巧,提高拍摄体验。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了2019年上半年内蒙古计算机软考考试的报名通知和考试时间。考试报名时间为3月1日至3月23日,考试时间为2019年5月25日。考试分为高级、中级和初级三个级别,涵盖了多个专业资格。报名采取网上报名和网上缴费的方式进行,报考人员可登录内蒙古人事考试信息网进行报名。详细内容请点击查看。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 近年来,大数据成为互联网世界的新宠儿,被列入阿里巴巴、谷歌等公司的战略规划中,也在政府报告中频繁提及。据《大数据人才报告》显示,目前全国大数据人才仅46万,未来3-5年将出现高达150万的人才缺口。根据领英报告,数据剖析人才供应指数最低,且跳槽速度最快。中国商业结合会数据剖析专业委员会统计显示,未来中国基础性数据剖析人才缺口将高达1400万。目前BAT企业中,60%以上的招聘职位都是针对大数据人才的。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 有没有一种方法可以在不继承UIAlertController的子类或不涉及UIAlertActions的情况下 ... [详细]
  • 本文介绍了如何使用python从列表中删除所有的零,并将结果以列表形式输出,同时提供了示例格式。 ... [详细]
author-avatar
琴瑟_0203
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有