什么是垃圾回收(转)

 

本文摘自我们几周后即将出版的Garbage Collection Handbook一书的样章。同时也让你能熟悉下垃圾回收的基础知识——这选自该书的第一章。 

乍一看,垃圾回收所做的事情应当恰如其名——查找并清除垃圾。事实上却恰恰相反。垃圾回收会跟踪所有仍在使用的对象,然后将剩余的对象标记为垃圾。牢记了这点之后,我们再来深入地了解下这个被称为“垃圾回收”的自动化内存回收在JVM中到底是如何实现的。 

手动管理内存 

在介绍现代版的垃圾回收之前,我们先来简单地回顾下需要手动地显式分配及释放内存的那些日子。如果你忘了去释放内存,那么这块内存就无法重用了。这块内存被占有了却没被使用。这种场景被称之为内存泄露。 

下面是用C写的一个手动管理内存的简单例子: 

Java代码 

  1. int send_request() {  
  2.     size_t n = read_size();  
  3.     int *elements = malloc(n * sizeof(int));  
  4.    
  5.     if(read_elements(n, elements) < n) {  
  6.         // elements not freed!  
  7.         return -1;  
  8.     }  
  9.    
  10.     // …  
  11.    
  12.     free(elements)  
  13.     return 0;  
  14. }  

可以看到,你很容易就会忘了释放内存。内存泄露曾经是个非常普遍的问题。你只能通过不断地修复自己的代码来与它们进行抗争。因此,需要有一种更优雅的方式来自动释放无用内存,以便减少人为错误的可能性。这种自动化过程又被称为垃圾回收(简称GC)。 

智能指针 
自动垃圾回收早期的一种实现便是引用计数。你知晓每一个对象被引用了几次,当计数器归0的时候,这个对象就可以被安全地回收掉了。C++的共享指针就是一个非常著名的例子: 

Java代码 

  1. int send_request() {  
  2.     size_t n = read_size();  
  3.     stared_ptr<vector<int>> elements   
  4.               = make_shared<vector<int>&gt();  
  5.    
  6.     if(read_elements(n, elements) < n) {  
  7.         return -1;  
  8.     }  
  9.    
  10.     return 0;  
  11. }  

我们使用的sharedptr会记录这个对象被引用的次数。如果你将它传递给别人则计数加一,当它离开了作用域后便会减一。一旦这个计数为0,sharedptr会自动地删除底层对应的vector。当然这只是个示例,因为也有读者指出来了,这个在现实中是不太可能出现的,但作为演示是足够了。 

自动内存管理 

在上面的C++代码中,我们还得显式地声明我们需要使用内存管理。那如果所有的对象都采用这个机制会怎样呢?那简直就太方便了,这样开发人员便无需考虑清理内存的事情了。运行时会自动知晓哪些内存不再使用了,然后释放掉它。也就是说,它自动地回收了这些垃圾。第一代的垃圾回收器是1959年Lisp引入的,这项技术迄今为止一直在不断演进。 

引用计数 
刚才我们用C++的共享指针所演示的想法可以应用到所有的对象上来。许多语言比如说Perl, Python以及PHP,采用的都是这种方式。这个通过一张图可以很容易说明: 

 

绿色的云代表的是程序中仍在使用的对象。从技术层面上来说,这有点像是正在执行的某个方法里面的局部变量,亦或是静态变量之类的。不同编程语言的情况可能会不一样,因此这并不是我们关注的重点。 

蓝色的圆圈代表的是内存中的对象,可以看到有多少对象引用了它们。灰色圆圈的对象是已经没有任何人引用的了。因此,它们属于垃圾对象,可以被垃圾回收器清理掉。 

看起来还不错对吧?没错,不过这里存在着一个重大的缺陷。很容易会出现一些孤立的环,它们中的对象都不在任何域内,但彼此却互相引用导致引用数不为0。下面便是一个例子: 

 

看到了吧,红色部分其实就是应用程序不再使用的垃圾对象。由于引用计数的缺陷,因此会存在内存泄露。 

有几种方法可以解决这一问题,比如说使用特殊的“弱”引用,或者使用一个特殊的算法回收循环引用。之前提到的Perl,Python以及PHP等语言,都是使用类似的方法来回收循环引用的,不过这已经超出本文讲述的范围了。我们准备详细介绍下JVM所采用的方法。 

标记删除 

首先,JVM对于对象可达性的定义要明确一些。它可不像前面那样用绿色的云便含糊了事的,而是有着非常明确及具体的垃圾回收根对象(Garbage Collection Roots)的定义: 

  • 局部变量
  • 活动线程
  • 静态字段
  • JNI引用
  • 其它(后面将会讨论到)

JVM通过标记删除的算法来记录所有可达(存活)对象,同时确保不可达对象的那些内存能够被重用。这包含两个步骤: 

  • 标记是指遍历所有可达对象,然后在本地内存中记录这些对象的信息
  • 删除会确保不可达对象的内存地址可以在下一次内存分配中使用。

JVM中的不同GC算法,比如说Parallel Scavenge,Parallel Mark+Copy, CMS都是这一算法的不同实现,只是各阶段略有不同而已,从概念上来讲仍然是对应着上面所说的那两个步骤。 

这种实现最重要的就是不会再出现泄露的对象环了: 

 

缺点就是应用程序的线程需要被暂停才能完成回收,如果引用一直在变的话你是无法进行计数的。这个应用程序被暂停以便JVM可以收拾家务的情况又被称为Stop The World pause(STW)。这种暂停被触发的可能性有很多,不过垃圾回收应该是最常见的一种。 

http://www.iteye.com/news/30630

 

时间: 2024-08-01 13:47:54

什么是垃圾回收(转)的相关文章

了解 CMS 垃圾回收日志

原文地址   作者: poonam 译者:严亮 校对:梁海舰 在CMS GC 时,使用参数-XX:+PrintGCDetails 和 -XX:+PrintGCTimeStamps 会输出很多日志信息,了解这些信息可以帮我们更好的调整参数,以获得更高的性能. 我们来看下在JDK1.4.2_10 中CMS GC日志示例: 39.910: [GC 39.910: [ParNew: 261760K->0K(261952K), 0.2314667 secs] 262017K->26386K(104838

JVM垃圾回收描述

垃圾回收分多级,0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾:1级或以上为部分垃圾回收,只会回收Young中的垃圾,内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况. 当一个URL被访问时,内存申请过程如下: JVM会试图为相关Java对象在Eden中初始化一块内存区域 当Eden空间足够时,内存申请结束.否则到下一步 JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收):释放后若Eden空间仍然不足以放入新对象,则试图将

浅谈PHP 5中垃圾回收算法的演化

PHP是一门托管型语言,在PHP编程中程序员不需要手工处理内存资源的分配与释放(使用C编写PHP或Zend扩展除外),这就意味着PHP本身实现了垃圾回收机制(Garbage Collection).现在如果去PHP官方网站(php.net)可以看到,目前PHP5的两个分支版本PHP5.2和PHP5.3是分别更新的,这是因为许多项目仍然使用5.2版本的PHP,而5.3版本对5.2并不是完全兼容.PHP5.3在PHP5.2的基础上做了诸多改进,其中垃圾回收算法就属于一个比较大的改变.本文将分别讨论P

浅谈PHP5中垃圾回收算法(Garbage Collection)的演化

前言:PHP是一门托管型语言,在PHP编程中程序员不需要手工处理内存资源的分配与释放(使用C编写PHP或Zend扩展除外),这就意味着PHP本身实现了垃圾回收机制(Garbage Collection).现在如果去PHP官方网站(php.net)可以看到,目前PHP5的两个分支版本PHP5.2和PHP5.3是分别更新的,这是因为许多项目仍然使用5.2版本的PHP,而5.3版本对5.2并不是完全兼容.PHP5.3在PHP5.2的基础上做了诸多改进,其中垃圾回收算法就属于一个比较大的改变.本文将分别

析JAVA之垃圾回收机制

本文为2010年编写,所以有很多看法不是很准确,有一定的参考价值,如需要更加深入细节,请参看,2012年编写的关于JVM的文章: 认识JVM--第一篇-对象生成&回收算法 认识JVM--第二篇-java对象内存模型 JVM第三篇(简单demo) 系统架构-性能篇章1(应用系统性能2-OOM&参数配置) 相继的还会有更多的java深入的知识和机制. 对于JAVA编程和很多类似C.C++语言有一个巨大区别就是内存不需要自己去free或者delete,而是由JVM垃圾回收机制去完成的.对于这个过

.NET中的垃圾回收

GC的全称是garbage collection,中文名称垃圾回收,是.NET中对内存管理的一种功能.垃圾回收器跟踪并回收托管内存中分配的对象,定期执行垃圾回收以回收分配给没有有效引用的对象的内存.当使用可用内存不能满足内存请求时,GC会自动进行. GC的全称是garbage collection,中文名称垃圾回收,是.NET中对内存管理的一种功能.垃圾回收器跟踪并回收托管内存中分配的对象,定期执行垃圾回收以回收分配给没有有效引用的对象的内存.当使用可用内存不能满足内存请求时,GC会自动进行.

从小处看C#.net垃圾回收

如果不用MDI来实现一个主窗体打开多个子窗体时, 从一个窗体(主窗体)打开一个(only one) 另外一个的窗体(子窗体)的实现 父窗体:MainForm public partial class MainForm:Form {     ............     private void menuItem1_Load(object sender,EventArgs e)          {         ChildForm child1=ChildForm.Create();   

对.Net 垃圾回收的C#编程相关方面(Finalize 和Dispose(bool disposing)和 Dispose())的一些理解体会

编程 Finalize 和Dispose(bool disposing)和 Dispose() 的相同点: 这三者都是为了释放非托管资源服务的. Finalize 和 Dispose() 和Dispose(bool disposing)的不同点: Finalize是CRL提供的一个机制, 它保证如果一个类实现了Finalize方法,那么当该类对象被垃圾回收时,垃圾回收器会调用Finalize方法.而该类的开发者就必须在Finalize方法中处理 非托管资源的释放. 但是什么时候会调用Finali

【转载】关于垃圾回收机制

转载自[雨声论坛]原作:software_young ----------------------转载开始------------------------所谓垃圾回收机制,指的是内存和各种变量或者目标所使用内存的释放和回收机制. 软件的发展历史,就是软件不断庞大.人力逐渐难以控制和对开发人员的技术要求逐渐降低的历史. 早先的许多软件,都是用汇编语言写的,汇编是机器码的助记符方式,因此,用汇编编程,实际就是用机器码编程.它要求程序员对机器非常熟悉才行,否则很难编出能用的程序. 那时候的程序员首先要

Java进阶学习(十) 内存管理与垃圾回收

整个教程中已经不时的出现一些内存管理和垃圾回收的相关知识.这里进行一个小小的总结. Java是在JVM所虚拟出的内存环境中运行的.内存分为栈(stack)和堆(heap)两部分.我们将分别考察这两个区域. 栈 栈的基本概念参考纸上谈兵: 栈 (stack).许多语言利用栈数据结构来记录函数调用的次序和相关变量(参考Linux从程序到进程). 在Java中,JVM中的栈记录了线程的方法调用.每个线程拥有一个栈.在某个线程的运行过程中,如果有新的方法调用,那么该线程对应的栈就会增加一个存储单元,即帧