使用Objective-C分布式对象的内存管理:我的临时实例永远活着!

使用Objective-C分布式对象的内存管理:我的临时实例永远活着!

问题描述:

我在玩Objective-C 分布式对象和我有一些问题,了解如何内存管理在系统下工作。下面的示例说明了我的问题:

I'm playing with Objective-C Distributed Objects and I'm having some problems understanding how memory management works under the system. The example given below illustrates my problem:

Protocol.h

#import <Foundation/Foundation.h>

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

Server.m b
$ b

Server.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;
}

Client.m
$ b

Client.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;
}

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

The issue is that any remote objects created by the root proxy are not released when their proxy counterparts in the client go out of scope. According to the documentation:


当对象的远程代理被释放时,会向接收者发送一条消息通知它

When an object’s remote proxy is deallocated, a message is sent back to the receiver to notify it that the local object is no longer shared over the connection.

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

I would therefore expect that as each DOTarget goes out of scope (each time around the loop) it's remote counterpart would be dellocated, since there is no other reference to it being held on the remote side of the connection.

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

In reality this does not happen: the temporary objects are only deallocate when the client application quits, or more accurately, when the connection is invalidated. I can force the temporary objects on the remote side to be deallocated by explicitly invalidating the NSConnection object I'm using each time around the loop and creating a new one but somehow this just feels wrong.

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

Is this the correct behaviour from DO? Should all temporary objects live as long as the connection that created them? Are connections therefore to be treated as temporary objects which should be opened and closed with each series of requests against the server?

任何见解都将不胜感激。

Any insights would be appreciated.

不要调用autorelease。只允许createTarget返回而不保留,并假定当代理在客户端上被释放时对象将被释放。当Connection对象做它的魔术,并返回一个代理到客户端,它保留在它的localObjects属性中的服务器本地对象。这样当客户端的代理超出范围时,Connection将释放本地对象,不需要自动释放。

Try not calling "autorelease" at all. Just allow the "createTarget" to return without retaining and assume that the object will be released when the proxy gets released on the client. When the Connection object does it's magic and returns a proxy to the client, it retains the server-local object in it's "localObjects" attribute. This way when the client's proxy goes out of scope, the Connection will release the local object, no need for autoreleasing.

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

I'm not really sure I'm correct but it seems like a valid explanation and while it seems a little strange to not call autorelease, this is DO which is a bit different. Even though the server is actually creating the object, it does not own it because the client created it (although remotely).


  • 客户端拥有

  • 客户端负责保留/释放代理

  • 代理和服务器生命周期中的对象,

  • 所有内存管理都应由启动分配的同一实体(在本例中为客户端)完成

  • 方便方法远程创建对象时,这将调用自动释放

  • The client owns the object, because it created it
  • The client is responsible for retain/release of the proxy
  • The proxy and the object on the server's life-cycle are one and the same
  • All memory management should be done by the same entity that initiates allocation (in this case the client)
  • Never use "convenience" methods when creating objects remotely as this will call an autorelease

这是非常可悲的是如何稀有任何解释如何DO内存应该由客户端创建时处理。

It's rather pathetic how scarce any explanation of how DO memory should be handled when created by the client.