zoukankan      html  css  js  c++  java
  • ANSI-C 中使用引用计数(译)

    ANSI-C中使用引用计数(译)

    原作者:Jean-David Gadina

    原文地址:Reference counting in ANSI-C

    关于

    内存管理在编写c程序时是一件困难的事情,

    某些高等级的编程语言提供了不同的内存管理的方法。

    主要有垃圾回收garbage collection) 和 引用计数reference counting)。

    本文将教给你如何在c语言中实现引用计数的内存管理系统。

    从个人角度讲,本人(原文章作者)作为一名使用c语言和Objective-c语言的程序员,更加偏爱引用计数的方法。

    因为这种方法隐含着对象所有权的概念。(It implies the notion of ownership on objects.)

    Objective-C 的例子

    在Objective-C中,当你通过 alloc 或者 copy 方法创建一个对象时,你拥有这个对象(you own the object)。这也就意味着将由你来负责释放(release)你的对象,保证该块内存被回收利用。 

    另外,对象也可以被保留(retained)。这种情况下他们也必须被释放(release)。 

    通过简便的方法获得对象,调用者并不拥有该对象,所以也没有必要去释放他们,释放的工作自然会由其他的类或者方法来做。 

    例如:

    1 NSArray * object1 = [ NSArray array ];
    2 NSArray * object2 = [ [ NSArray alloc ] init ];
    3 NSArray * object3 = [ [ [ NSArrayarray ] retain ] retain ];

    在这里,变量 object2 需要被release,因为我们明确的通过 alloc 创建了它。

    变量object3 则需要被release 两次,因为我们retain 了它两次。

    如下:

    1 [ object2 release ];
    2 [ [ object3 release ] release ];

    C 语言实现

    作为一名c语言编程者,原文作者将要使用ANSI-C来实现objective-c 中的引用计数。

    具体实施如下:

    首先,我们需要为我们的内存纪录定义一个结构体,这个结构体看起来像是下面这个样子:

    1 typedef struct
    2 {
    3 unsigned int retainCount
    4 void       * data;
    5 }
    6 MemoryObject;

    我们将 retain 计数 使用一个 无符号整形变量 rerainCount 来储存,遇到retain则增加改变量的值,遇到release 则减少改变量的值,当改变量的值为0的时候,就释放掉该对象的内存。 

    同时我们也需要自定义一个 分配函数(allocation function):

    1 void * Alloc( size_t size )
    2 {
    3     MemoryObject * o;
    4     o = ( MemoryObject * )calloc( sizeof( MemoryObject ) + size, 1 );

    我们最终是要返回内存对象的指针,所以我们需要进行一些计算: 

    第一、声明一个 指向char类型的指针,用来指向我们生成的内存对象结构体:

    1 char * ptr = ( char * )o; 

    第二、通过给该指针增加内存对象结构体的大小来获取 用户自定义数据的内存地址:

    2 ptr += sizeof( MemoryObject );

    第三、将用户自定义数据内存地址传给 内存对象结构体中的 data指针,然后将引用计数变量的值设置为1:

    3 o->data        = ptr;
    4 o->retainCount = 1;

    最后,返回ptr指针,这样使用者就不需要知道我们内存对象结构体的内部结构了。

    5 return ptr;

    下面是完整的函数:

     1 void * Alloc( size_t size )
     2 {
     3     MemoryObject * o;
     4     char         * ptr;
     5     o              = ( MemoryObject * )calloc( sizeof( MemoryObject ) + size, 1 );
     6     ptr            = ( char * )o;
     7     ptr           += sizeof( MemoryObject );
     8     o->retainCount = 1;
     9     o->data        = ptr;
    10     return ( void * )ptr;
    11 }

    这样,我们成功的返回了用户指定的内存大小,隐藏了定义在用户数据前面的结构体。

    要找回我们的数据(译者:应该是自定的结构体),只需要很简单的减去 MemoryObject 结构体 的大小即可:

    拿Retain 函数举例:

    1 void Retain( void * ptr )
    2 {
    3     MemoryObject * o;
    4     char         * cptr;
    5     cptr  = ( char * )ptr;
    6     cptr -= sizeof( MemoryObject );
    7     o     = ( MemoryObject * )cptr;   
    8     o->retainCount++:
    9

    在这里通过用户指针减去 MemoryObject 结构体的大小获得了,指向咱们之前自定义的结构体的地址,然后访问其中的 retainCount 变量,来增加引用计数。

    Release 方法也是一样:

     1 void Release( void * ptr )
     2 {
     3     MemoryObject * o;
     4     char         * cptr;
     5     cptr  = ( char * )ptr;
     6     cptr -= sizeof( MemoryObject );
     7     o     = ( MemoryObject * )cptr;
     8     o->retainCount--:
     9     if( o->retainCount == 0 )
    10     {
    11         free( o );
    12     }
    13 }

    当引用计数为0时,释放掉对象。

    到此为止,我们已经拥有了一个 基于c语言的引用计数内存管理机制。

    所要做的就是 使用 Alloc 创建对象,在需要的时候 Retain,在不需要的时候 Release.

    某些情况下 对象已经被其他函数引用(retain),但这时你已经不必在意该对象是否会被正确释放,因为你已经不再拥有它了(It may have been retained by another function, but then you don't have to care if it will be freed or not, as you don't own the object anymore)。

     (转载请标明出处:点我

  • 相关阅读:
    conda环境配置以及pyinstaller报错配置
    软件测试的艺术--读书笔记
    flex布局相关
    移动端特殊样式
    css3中的2D转换
    logo seo优化
    html5 简单的新特性
    css中溢出文字省略号方式
    css用户界面样式
    精灵图与字体图标相关
  • 原文地址:https://www.cnblogs.com/csusheep/p/3193639.html
Copyright © 2011-2022 走看看