1

我正在使用 Objective-C分布式对象,并且在理解内存管理在系统下的工作方式时遇到了一些问题。下面给出的示例说明了我的问题:

协议.h

#import <Foundation/Foundation.h>

@protocol DOServer
- (byref id)createTarget;
@end

服务器.m

#import <Foundation/Foundation.h>
#import "Protocol.h"


@interface DOTarget : NSObject
@end


@interface DOServer : NSObject < DOServer >
@end


@implementation DOTarget

- (id)init
{
    if ((self = [super init]))
    {
        NSLog(@"Target created");
    }
    return self;
}

- (void)dealloc
{
    NSLog(@"Target destroyed");
    [super dealloc];
}

@end

@implementation DOServer

- (byref id)createTarget
{
    return [[[DOTarget alloc] init] autorelease];
}

@end


int main()
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    DOServer *server = [[DOServer alloc] init];

    NSConnection *connection  = [[NSConnection new] autorelease];
    [connection setRootObject:server];
    if ([connection registerName:@"test-server"] == NO)
    {
        NSLog(@"Failed to vend server object");
    }
    else
    {
        while (YES)
        {
            NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
            [[NSRunLoop currentRunLoop] runUntilDate:
                 [NSDate dateWithTimeIntervalSinceNow:0.1f]];
            [innerPool drain];
        }
    }

    [pool drain];
    return 0;
}

客户端.m

#import <Foundation/Foundation.h>
#import "Protocol.h"

int main()
{
    unsigned i = 0;
    for (; i < 3; i ++)
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        id server = [NSConnection rootProxyForConnectionWithRegisteredName:@"test-server"
                                                                      host:nil];
        [server setProtocolForProxy:@protocol(DOServer)];
        NSLog(@"Created target: %@", [server createTarget]);

        [[NSRunLoop currentRunLoop] runUntilDate:
             [NSDate dateWithTimeIntervalSinceNow:1.0]];
        [pool drain];
    }
    return 0;
}

问题是当客户端中的代理对应对象超出范围时,根代理创建的任何远程对象都不会被释放。根据文档

当对象的远程代理被解除分配时,会向接收者发送一条消息,通知它本地对象不再通过连接共享。

因此,我希望当每个DOTarget都超出范围时(每次在循环周围),它的远程对应物将被解除分配,因为在连接的远程端没有其他对它的引用。

实际上这不会发生:临时对象仅在客户端应用程序退出时释放,或者更准确地说,在连接无效时释放。我可以通过显式地使我每次在循环中使用的 NSConnection 对象无效并创建一个新对象来强制释放远程端的临时对象,但不知何故这感觉不对。

这是 DO 的正确行为吗?所有临时对象都应该与创建它们的连接一样长吗?因此,连接是否应被视为临时对象,应在针对服务器的每一系列请求中打开和关闭?

任何见解将不胜感激。

4

2 回答 2

0

尽量不要调用“自动释放”。只允许“createTarget”返回而不保留,并假设当代理在客户端释放时对象将被释放。当 Connection 对象执行它并返回一个代理给客户端时,它会在它的“localObjects”属性中保留服务器本地对象。这样,当客户端的代理超出范围时,Connection 将释放本地对象,无需自动释放。

我不确定我是否正确,但这似乎是一个有效的解释,虽然不调用 autorelease 似乎有点奇怪,但这是 DO 有点不同。尽管服务器实际上是在创建对象,但它并不拥有它,因为客户端创建了它(尽管是远程创建的)。

  • 客户拥有该对象,因为它创建了它
  • 客户端负责保留/释放代理
  • 服务器生命周期中的代理和对象是一回事
  • 所有内存管理都应由启动分配的同一实体(在本例中为客户端)完成
  • 远程创建对象时切勿使用“方便”方法,因为这将调用自动释放

相当可悲的是,在客户端创建时应该如何处理 DO 内存的任何解释都很少。

于 2010-04-22T21:42:48.873 回答
0

您服务器上的自动释放池永远不会耗尽,因此您的自动释放对象永远不会“超出范围”。您将始终对它们有额外的参考。设置您的服务器,类似于您在客户端中设置的测试(大约每秒转储一次运行循环),每次都排空并建立一个新的内部池。然后,您将看到预期的结果。

于 2010-03-26T06:45:22.050 回答