二值图像连通域标记算法

二值图像连通域标记算法

八邻域标记算法:

1)   判断此点八邻域中的最左,左上,最上,上右点的情况。如果都没有点,则表示一个新的区域的开始。

2)   如果此点八邻域中的最左有点,上右都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。

3)   如果此点八邻域中的左上有点,上右都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。

4)   否则按照最左,左上,最上,上右的顺序,标记此点为四个中的一个。

BOOL  CImageColorProcess::ConnectedLabelTwoPass(LPBYTE lpSrc, LPBYTE lpDst, int nSrcCount, int nW, int nH)
{
	if (nSrcCount != 24)
	{
		AfxMessageBox("非rgb图像,不处理!");
		return false;
	}
	LPBYTE m_lpImgBitsMove;
	int * m_lpnMark;            //标记数组指针
	int * m_lpnMarkMove;       //标记数组移动指针
	int m_nMarkNumbers;       //标记的区域个数
	m_lpnMark = NULL;
	if (m_lpnMark == NULL)
	{
		m_lpnMark = new int[nW*nH];
		ASSERT(m_lpnMark != NULL);
		m_lpnMarkMove = m_lpnMark;
	}
	::memset((LPBYTE)m_lpnMark, 0, nW*nH * 4);

	int nMarkValue = 1;//每次标识的值,nMarkValue会在后边递增,来表示不同的区域,从1开始标记。
	int nMaxMarkValue = 0;     //记录最大的标识的值
	int i, j;                 //循环控制变量   

	/* 定义存放等价对的链表,其元素是 EqualMark类型,
	定义list是为了节约存储空间。要使用Clist,
	应该#include <Afxtempl.h>。  */
	CList < EqualMark, EqualMark > lEqualMark;

	//初始化图像移动指针
	m_lpImgBitsMove = lpDst;

	/*进行第一次扫描,将所得的等价对(EqualMark类型)加到lEqualMark链表中。
	使用nMarkValue来进行每一次新的标记,标记之后将其值加1。
	由于版面关系,这部分代码也同样略去不写。作者提出以下几点编程时要注意
	的地方。
	Note1:图像的四周像素并不会有8个相邻的像素。这时就要根据上、下、左、
	右四种不同的情况做不同的寻找等价对的判断。
	Note2:可以先对等价对进行排序,每次都保证MarkValue1<MarkValue2,
	这样易于管理等价对。
	Note3:在实际工作中,连续寻找出的等价对很容易重复,将本次找出的等价对
	和链表中保存的最后一个等价对相比较,如果不相等的话再存入等价对链表,
	这样可以大大降低链表中等价对的重复。
	Note4:第一次扫描之后,nMarkValue-1即为nMaxMarkValue。 */

	/************************************************************************/
	//下面为补充代码,完成对图象的第一次扫描   

	//初始化图象数组和标识数组的指针
	int nEqualNum = 0;
	EqualMark tempEqualMark;    //用以暂时存放每次找到的等价关系
	m_lpnMarkMove = m_lpnMark;
	//m_lpImgBitsMove = m_lpImgBits;

	int bObjectGray = 0;
	//标记图象的第一行、第一列的象素(只有这一个象素)
	if (*m_lpImgBitsMove == bObjectGray)
	{
		*m_lpnMarkMove = nMarkValue++;
	}
	m_lpnMarkMove++;
	m_lpImgBitsMove++;

	//标记图象的第一行,此时不会出现等价的情况
	for (i = 1; i <= nW; i++)
	{
		//需要标记的情况
		if (*m_lpImgBitsMove == bObjectGray)
		{
			//前面没有被标记过,则开始一个新的标记
			if (*(m_lpnMarkMove - 1) == 0)
			{
				*m_lpnMarkMove = nMarkValue++;
			}
			//前面被标记过,则跟随前一个标记
			else
			{
				*m_lpnMarkMove = *(m_lpnMarkMove - 1);
			}
		}
		m_lpnMarkMove++;
		m_lpImgBitsMove++;
	}

	//除第一行之外的标记,此时会出现等价的关系
	for (j = 1; j <= nH; j++)
	{
		m_lpImgBitsMove = lpDst + j*nW;
		m_lpnMarkMove = m_lpnMark + j*nW;

		//对每行的第一个点做处理,总体就是对图象的最左列做处理
		//只需要检视上,右上两个点
		if (*m_lpImgBitsMove == bObjectGray)
		{
			//<上>位置被标记过
			if (*(m_lpnMarkMove - nW) != 0)
			{
				//跟随<上>标记
				*m_lpnMarkMove = *(m_lpnMarkMove - nW);
				if (*(m_lpnMarkMove - nW) != *(m_lpnMarkMove - nW + 1) && *(m_lpnMarkMove - nW + 1) != 0)
				{
					//<上><右上>等价标记
					AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - nW),
						*(m_lpnMarkMove - nW + 1), nEqualNum, lEqualMark);
				}

			}
			//<上>没有标记,此时一定不会存在等价关系
			else
			{
				if (*(m_lpnMarkMove - nW + 1) != 0)
				{
					*m_lpnMarkMove = *(m_lpnMarkMove - nW + 1);   //跟随<右上>标记
				}
				//<上>、<右上>都没有标记,则开始新的标记
				else
				{
					*m_lpnMarkMove = nMarkValue++;
				}
			}
		}
		m_lpnMarkMove++;
		m_lpImgBitsMove++;

		//对每行的中间点做标记处理,此时存在<左>、<左上>、<上>、<右上> 4种情况
		for (i = 1; i <= nW - 1; i++)
		{
			//需要标记
			if ((*m_lpImgBitsMove) == bObjectGray)
			{
				//<左>被标记过
				if (*(m_lpnMarkMove - 1) != 0)
				{
					*m_lpnMarkMove = *(m_lpnMarkMove - 1);          //跟随<左>   

					if (*(m_lpnMarkMove - 1) != *(m_lpnMarkMove - nW - 1) && *(m_lpnMarkMove - nW - 1) != 0)
					{
						//标记<左>、<左上>等价
						AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - 1),
							*(m_lpnMarkMove - nW - 1), nEqualNum, lEqualMark);
					}

					if (*(m_lpnMarkMove - 1) != *(m_lpnMarkMove - nW) && *(m_lpnMarkMove - nW) != 0)
					{
						//标记<左>、<上>等价
						AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - 1),
							*(m_lpnMarkMove - nW), nEqualNum, lEqualMark);
					}

					if (*(m_lpnMarkMove - 1) != *(m_lpnMarkMove - nW + 1) && *(m_lpnMarkMove - nW + 1) != 0)
					{
						//标记<左>、<右上>等价
						AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - 1),
							*(m_lpnMarkMove - nW + 1), nEqualNum, lEqualMark);
					}
				}
				//<左>未被标记过
				else
				{
					//<左上>被标记过
					if (*(m_lpnMarkMove - nW - 1) != 0)
					{
						*m_lpnMarkMove = *(m_lpnMarkMove - nW - 1);

						if (*(m_lpnMarkMove - nW - 1) != *(m_lpnMarkMove - nW) && *(m_lpnMarkMove - nW) != 0)
						{
							//标记<左上>、<上>等价
							AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - nW - 1),
								*(m_lpnMarkMove - nW), nEqualNum, lEqualMark);
						}

						if (*(m_lpnMarkMove - nW - 1) != *(m_lpnMarkMove - nW + 1) && *(m_lpnMarkMove - nW + 1) != 0)
						{
							//标记<左上>、<右上>等价
							AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - nW - 1),
								*(m_lpnMarkMove - nW + 1), nEqualNum, lEqualMark);
						}

					}
					//<左>、<左上>未标记过
					else
					{
						if (*(m_lpnMarkMove - nW) != 0)
						{
							*m_lpnMarkMove = *(m_lpnMarkMove - nW);            //跟随<上>标记   

							if (*(m_lpnMarkMove - nW) != *(m_lpnMarkMove - nW + 1) && *(m_lpnMarkMove - nW + 1) != 0)
							{
								//标记<上>和<右上>等价
								AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - nW),
									*(m_lpnMarkMove - nW + 1), nEqualNum, lEqualMark);
							}
						}
						//<左>、<左上>、<上>未标记过,此时不存在等价关系
						else
						{
							if (*(m_lpnMarkMove - nW + 1) != 0)
							{
								*m_lpnMarkMove = *(m_lpnMarkMove - nW + 1);      //跟随<右上>标记
							}
							//<左>、<左上>、<上>、<右上>未标记过,则开始新的标记值
							else
							{
								*m_lpnMarkMove = nMarkValue++;
							}

						}    //<左>、<左上>、<上>未标记过结束
					}   //<左>、<左上>未标记过结束
				}  //<左>未被标记过结束
			}     // else 不需要标记   

			m_lpnMarkMove++;
			m_lpImgBitsMove++;
		}       //中间点处理的结束   

		//对每行的最后一个点做处理,总体就是对图象的最左列做处理
		//此时存在<左>、<左上>、<上> 3种情况   

		//需要标记
		if ((*m_lpImgBitsMove) == bObjectGray)
		{
			//<左>被标记过
			if (*(m_lpnMarkMove - 1) != 0)
			{
				*m_lpnMarkMove = *(m_lpnMarkMove - 1);

				if (*(m_lpnMarkMove - 1) != *(m_lpnMarkMove - nW - 1) && *(m_lpnMarkMove - nW - 1) != 0)
				{
					//标记<左>、<左上>等价
					AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - 1),
						*(m_lpnMarkMove - nW - 1), nEqualNum, lEqualMark);
				}

				if (*(m_lpnMarkMove - 1) != *(m_lpnMarkMove - nW) && *(m_lpnMarkMove - nW) != 0)
				{
					//标记<左>、<上>等价
					AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - 1),
						*(m_lpnMarkMove - nW), nEqualNum, lEqualMark);
				}

			}
			//<左>未被标记过
			else
			{
				if (*(m_lpnMarkMove - nW - 1) != 0)
				{
					*m_lpnMarkMove = *(m_lpnMarkMove - nW - 1);    //跟随<左上>   

					if (*(m_lpnMarkMove - nW - 1) != *(m_lpnMarkMove - nW) && *(m_lpnMarkMove - nW) != 0)
					{
						//标记<左上>、<上>等价
						AttachEqualMark(tempEqualMark, *(m_lpnMarkMove - nW - 1),
							*(m_lpnMarkMove - nW), nEqualNum, lEqualMark);
					}

				}
				//<左>、<左上>未标记过
				else
				{
					if (*(m_lpnMarkMove - nW) != 0)
					{
						*m_lpnMarkMove = *(m_lpnMarkMove - nW);    //跟随<上>标记
					}
					//<左>、<左上>、<上>未标记过,则开始新的标记值
					else
					{
						*m_lpnMarkMove = nMarkValue++;
					}

				}
			}
		}  //对每行的最后一个点做处理,总体就是对图象的最左列做处理   

	}     //"除第一行之外的标记"的结束   

	//因为在每次标记完之后,nMarkValue都会自动++
	//所以要通过(-1)操作来记录所标记的最大的个数   

	nMaxMarkValue = nMarkValue - 1;
	/************************************************************************/
	/* 定义双层链表的外层链表,它的元素是一个指向内层链表的指针。
	内层链表的型别也是CptrList,其元素是标记值。 */
	CPtrList exList;
	CPtrList * pInnerList;
	POSITION posExElem;

	if (lEqualMark.GetCount() != 0)
	{
		// pInnerListAdd,每次向exList中添加的新元素
		CPtrList * pInnerListAdd = new CPtrList;
		ASSERT(pInnerListAdd != NULL);

		/* 添加第一个等价对到exList的第一个元素所指向的InnerList中。  */
		pInnerListAdd->AddTail((void *)lEqualMark.GetHead().MarkValue1);
		pInnerListAdd->AddTail((void *)lEqualMark.GetHead().MarkValue2);
		exList.AddTail((void *)pInnerListAdd);
		lEqualMark.RemoveHead();

		/* 定义pFindValue1和pFindValue2, 存放在所有内层链表中找到特定值
		的某个内层链表的头指针,也就是外层链表的某个元素值。 */
		CPtrList * pFindValue1 = NULL;
		CPtrList * pFindValue2 = NULL;

		//整理剩余的等价对
		while (!lEqualMark.IsEmpty())
		{
			posExElem = exList.GetHeadPosition();
			pFindValue1 = NULL;
			pFindValue2 = NULL;

			while (posExElem)
			{
				pInnerList = (CPtrList *)exList.GetAt(posExElem);
				if (pInnerList->Find((void *)lEqualMark.GetHead().MarkValue1))
				{
					pFindValue1 = pInnerList;
				}
				if (pInnerList->Find((void *)lEqualMark.GetHead().MarkValue2))
				{
					pFindValue2 = pInnerList;
				}
				exList.GetNext(posExElem);
			}

			//该等价对中两个值都在已经整理过的等价关系中
			if (pFindValue1 && pFindValue2)
			{
				//当两个地址不一样时,对链表进行调整
				if (pFindValue1 != pFindValue2)
				{
					pFindValue1->AddTail(pFindValue2);
					/* 清除链表元素,通过new得到的CptrList 类型,
					必须采用delete进行删除,否则会造成内存泄露。*/
					POSITION posDelete = exList.Find((void *)pFindValue2);
					pFindValue2->RemoveAll();
					delete pFindValue2;
					exList.RemoveAt(posDelete);
				}
			}
			/* 只在已经整理过的等价关系中找到Value1,
			那么将Vaule2加到Value1所在的链表中。 */
			else if (pFindValue1)
			{
				pFindValue1->AddTail((void *)lEqualMark.GetHead().MarkValue2);
			}
			else if (pFindValue2)
			{
				pFindValue2->AddTail((void *)lEqualMark.GetHead().MarkValue1);
			}
			/* 等价对中两个值在整理过的等价关系中都
			没有找到,则在exList中增加新元素。 */
			else
			{
				CPtrList * pInnerListAdd = new CPtrList;
				pInnerListAdd->AddTail((void *)lEqualMark.GetHead().MarkValue1);
				pInnerListAdd->AddTail((void *)lEqualMark.GetHead().MarkValue2);
				exList.AddTail((void *)pInnerListAdd);
			}
			//去掉此时等价对的头元素
			lEqualMark.RemoveHead();
		}  // while ( !lEqualMark.IsEmpty() )循环结束
	}  // if ( lEqualMark.GetCount() !=0 )语句结束
	/* 等价对链表大小为0,说明第一次扫描之后没有产生等价对,标记已经完成。 */
	else
	{
		return TRUE;
	}

	/*等价关系整理完成,下面建立第一次扫描的标记值和
	第二次扫描的标记值之间的映射关系。*/

	int nTotalEqualNum = 0; //列入等价关系的标记个数
	int nMarkRegion = 0;   //图像中连通区域个数   

	posExElem = exList.GetHeadPosition();
	while (posExElem)
	{
		pInnerList = (CPtrList *)exList.GetAt(posExElem);
		nTotalEqualNum += pInnerList->GetCount();
		exList.GetNext(posExElem);
	}
	nMarkRegion = nMaxMarkValue - nTotalEqualNum + exList.GetCount();

	/* 定义第一次扫描和第二次扫描之间的映射向量,要使用vector,
	应该#include <vector>并且使用std命名空间。 */
	vector<MarkMapping> vMarkMap(nMaxMarkValue);

	//初始化映射向量,令其做自身映射
	for (i = 0; i < nMaxMarkValue; i++)
	{
		vMarkMap[i].nOriginalMark = i + 1;
		vMarkMap[i].nMappingMark = i + 1;
	}

	POSITION posInnerElem; //InnerList中元素的位置
	int nMin;              //InnerList中最小值
	int nIndex = 0;

	posExElem = exList.GetHeadPosition();
	/* while循环实现了如下功能:找到每个等价组中最小的标记值,
	然后将映射向量中nMappingMark设定为其所在等价组的最小的标记值。*/
	while (posExElem)
	{
		pInnerList = (CPtrList *)exList.GetAt(posExElem);
		nMin = (int)pInnerList->GetHead();
		posInnerElem = pInnerList->GetHeadPosition();
		pInnerList->GetNext(posInnerElem);

		while (posInnerElem)
		{
			if ((int)pInnerList->GetAt(posInnerElem) < nMin)
			{
				nMin = (int)pInnerList->GetAt(posInnerElem);
			}
			pInnerList->GetNext(posInnerElem);
		}

		/* 根据每组等价关系中的最小的标记值对Mapping向量做出调整。 */
		posInnerElem = pInnerList->GetHeadPosition();
		while (posInnerElem)
		{
			nIndex = (int)pInnerList->GetAt(posInnerElem) - 1;
			vMarkMap[nIndex].nMappingMark = nMin;
			pInnerList->GetNext(posInnerElem);
		}
		exList.GetNext(posExElem);
	}

	/* 将映射向量nMappingMark中不重复的部分找出并对其进行排序。
	使用find()和sort()这两种泛型算法,应该#include <algorithm>。*/
	vector <int> vSortMark(nMarkRegion); //排序向量
	nIndex = 0;

	for (i = 0; i < nMaxMarkValue; i++)
	{
		if (find(vSortMark.begin(), vSortMark.end(), vMarkMap[i].nMappingMark)
			== vSortMark.end())
		{
			vSortMark[nIndex++] = vMarkMap[i].nMappingMark;
		}
	}
	sort(vSortMark.begin(), vSortMark.end());

	/* 根据排序后的标记在vSortMark向量中的位置,对映射向量做出重新调整。 */
	vector<int>::iterator itFind;
	vector<int>::iterator itBegin;
	itBegin = vSortMark.begin();

	for (i = 0; i < nMaxMarkValue; i++)
	{
		itFind = find(vSortMark.begin(), vSortMark.end(), vMarkMap[i].nMappingMark);
		vMarkMap[i].nMappingMark = (itFind - itBegin + 1);
	}

	//根据映射向量对标记数组进行调整
	for (j = 0; j < nH; j++)
	{
		m_lpnMarkMove = m_lpnMark + j*nW;
		for (i = 0; i < nW; i++)
		{
			if (*m_lpnMarkMove != 0)
			{
				*m_lpnMarkMove = vMarkMap[*m_lpnMarkMove - 1].nMappingMark;
			}
			m_lpnMarkMove++;
		}
	}

	//删除链表结构中通过new得到的元素
	posExElem = exList.GetHeadPosition();
	while (posExElem)
	{
		pInnerList = (CPtrList *)exList.GetAt(posExElem);
		pInnerList->RemoveAll();
		delete pInnerList;
		exList.GetNext(posExElem);
	}
	exList.RemoveAll();

	//通过类成员变量来记录连通区域的个数
	m_nMarkNumbers = nMarkRegion;
	CString s;
	s.Format("连通区域个数为%d\n", nMarkRegion);
	AfxMessageBox(s);
	return (long)TRUE;

}

成功识别为6个

时间: 2024-10-07 21:16:56

二值图像连通域标记算法的相关文章

二值图像连通域标记算法与代码

这里列举二值图像连通域标记算法包括直接扫描标记算法和二值图像连通域标记快速算法 一.直接扫描标记算法把连续区域作同一个标记,常见的四邻域标记算法和八邻域标记算法. 1.  四邻域标记算法: 1)   判断此点四邻域中的最左,最上有没有点,如果都没有点,则表示一个新的区域的开始. 2)   如果此点四邻域中的最左有点,最上没有点,则标记此点为最左点的值:如果此点四邻域中的最左没有点,最上有点,则标记此点为最上点的值. 3)   如果此点四邻域中的最左有点,最上都有点,则标记此点为这两个中的最小的标

实现基于C语言的二值图像连通域标记算法

实现基于C语言的二值图像连通域标记算法 1 #include <stdio.h> 2 #include <stdarg.h> 3 #include <stddef.h> 4 #include <stdlib.h> 5 #include <stdint.h> 6 #include <math.h> 7 8 #define CONNECTIVITY4 4 9 #define CONNECTIVITY8 8 10 #define STACK

连通域标记算法并行化(MPI+OpenMP)

1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出来,为不同的连通域填入数字标记,并且统计连通域的数目.通过对栅格图像中进行连通域标记,可用于静态地分析各连通域斑块的分布,或动态地分析这些斑块随时间的集聚或离散,是图像处理非常基础的算法.目前常用的连通域标记算法有1)扫描法(二次扫描法.单向反复扫描法等).2)线标记法.3)区域增长法.二次扫描法由于简单通用而被广泛使用! 图1 连通域标记示意图 随着所要处理的数据量越来越

图像连通域标记算法研究

把之前一篇记录过的日志贴过来 图像连通域标记算法研究 ConnectedComponent Labeling 最近在研究一篇复杂下背景文字检测的论文. “Detecting Text in Natural Scenes with Stroke Width Transform ” CPVR 2010的文章,它主要探讨利用文字内部笔画宽度一致作为主要线索来检测文字的一个新奇的算法,当然,我不是想讨论文字检测,论文算法实施的过程中有一步涉及到图像连通域标记算法,在这里我遇到了一些问题,查阅了一些相关文

转-二值图像连通域标记

转自:图像分析:二值图像连通域标记 一.前言 二值图像,顾名思义就是图像的亮度值只有两个状态:黑(0)和白(255).二值图像在图像分析与识别中有着举足轻重的地位,因为其模式简单,对像素在空间上的关系有着极强的表现力.在实际应用中,很多图像的分析最终都转换为二值图像的分析,比如:医学图像分析.前景检测.字符识别,形状识别.二值化+数学形态学能解决很多计算机识别工程中目标提取的问题. 二值图像分析最重要的方法就是连通区域标记,它是所有二值图像分析的基础,它通过对二值图像中白色像素(目标)的标记,让

改进的二值图像像素标记算法及程序实现(含代码)

笔者实现了一个论文里面的算法程序,论文(可以网上搜索到,实在搜不到可以联系笔者或留下邮箱发给你)讲解比较到位,按照作者的思路写完了代码,测试效果很好,在此分享一下算法思路及实现代码. 此算法优于一般的像素标记算法,只需扫描一遍就可以得出图像边界.面积等等,大大减少了计算量. 算法描述: 一.全图扫描 对二值图像全图扫描,左到右,上到下,一遇到像素边界就进行判断.像素边界指当前像素灰度为1,其他8领域至少有一个灰度值为0. 1.先依次判断当前像素(i,j)的左侧.左上侧.上侧像素和右上侧像素是否被

二值图像连通域标记

来源:http://www.cnblogs.com/ronny/p/img_aly_01.html 一.前言 二值图像,顾名思义就是图像的亮度值只有两个状态:黑(0)和白(255).二值图像在图像分析与识别中有着举足轻重的地位,因为其模式简单,对像素在空间上的关系有着极强的表现力.在实际应用中,很多图像的分析最终都转换为二值图像的分析,比如:医学图像分析.前景检测.字符识别,形状识别.二值化+数学形态学能解决很多计算机识别工程中目标提取的问题. 二值图像分析最重要的方法就是连通区域标记,它是所有

OpenCV:二值图像连通区域分析与标记算法实现

编译环境: 操作系统:Win8.1  64位 IDE平台:Visual Studio 2013 Ultimate OpenCV:2.4.8 一.连通域 在图像中,最小的单位是像素,每个像素周围有8个邻接像素,常见的邻接关系有2种:4邻接与8邻接.4邻接一共4个点,即上下左右,如下左图所示.8邻接的点一共有8个,包括了对角线位置的点,如下右图所示.         如果像素点A与B邻接,我们称A与B连通,于是我们不加证明的有如下的结论: 如果A与B连通,B与C连通,则A与C连通. 在视觉上看来,彼

Java虚拟机(三)垃圾标记算法与Java对象的生命周期

相关文章 Java虚拟机系列 前言 这一节我们来简单的介绍垃圾收集器,并学习垃圾标记的算法:引用计数算法和根搜索算法,为了更好的理解根搜索算法,会在文章的最后介绍Java对象在虚拟机中的生命周期. 1.垃圾收集器概述 垃圾收集器(Garbage Collection),通常被称作GC.提到GC,很多人认为它是伴随Java而出现的,其实GC出现的时间要比Java早太多了,它是1960诞生于MIT的Lisp. GC主要做了两个工作,一个是内存的划分和分配,一个是对垃圾进行回收.关于内存的划分和分配,