1

Objective-C Distributed Objectsで遊んでいますが、システムでメモリ管理がどのように機能するかを理解するのに問題があります。以下の例は、私の問題を示しています。

プロトコル.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;
}

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

問題は、ルート プロキシによって作成されたリモート オブジェクトが、クライアント内の対応するプロキシがスコープ外になったときに解放されないことです。ドキュメントによると:

オブジェクトのリモート プロキシの割り当てが解除されると、受信者にメッセージが返され、ローカル オブジェクトが接続を介して共有されなくなったことを通知します。

したがってDOTarget、接続のリモート側で保持されている他の参照がないため、それぞれが範囲外になると (ループのたびに)、リモートの相手が割り当て解除されると予想されます。

実際には、これは起こりません。一時オブジェクトは、クライアント アプリケーションが終了したとき、またはより正確には、接続が無効になったときにのみ解放されます。ループのたびに使用している NSConnection オブジェクトを明示的に無効にして新しいオブジェクトを作成することで、リモート側の一時オブジェクトの割り当てを強制的に解除できますが、どういうわけかこれは間違っているように感じます。

これは DO の正しい動作ですか? すべての一時オブジェクトは、それらを作成した接続が続く限り存続する必要がありますか? したがって、接続は、サーバーに対する一連のリクエストごとに開いたり閉じたりする必要がある一時オブジェクトとして扱われますか?

任意の洞察をいただければ幸いです。

4

2 に答える 2

0

「自動解放」をまったく呼び出さないようにしてください。「createTarget」が保持せずに戻ることを許可し、プロキシがクライアントで解放されたときにオブジェクトが解放されると想定します。Connectionオブジェクトが魔法のように実行し、プロキシをクライアントに返す場合、サーバーローカルオブジェクトはその「localObjects」属性に保持されます。このように、クライアントのプロキシがスコープ外になると、Connectionはローカルオブジェクトを解放します。自動解放は必要ありません。

正しいかどうかはわかりませんが、それは有効な説明のようです。自動リリースを呼び出さないのは少し奇妙に思えますが、これは少し異なるDOです。サーバーは実際にオブジェクトを作成していますが、クライアントがオブジェクトを作成したため(リモートではありますが)、サーバーはオブジェクトを所有していません。

  • クライアントはオブジェクトを作成したため、オブジェクトを所有します
  • クライアントはプロキシの保持/解放に責任があります
  • サーバーのライフサイクル上のプロキシとオブジェクトは同一です
  • すべてのメモリ管理は、割り当てを開始するのと同じエンティティ(この場合はクライアント)によって実行される必要があります
  • オブジェクトをリモートで作成するときは、「便利な」メソッドを使用しないでください。これにより、自動リリースが呼び出されます。

クライアントによって作成されたときにDOメモリがどのように処理されるべきかについての説明がいかに少ないかはかなり哀れです。

于 2010-04-22T21:42:48.873 に答える
0

サーバー上の自動解放プールが空になることはないため、自動解放されたオブジェクトが「範囲外」になることはありません。それらへの追加の参照が常にあります。クライアントで設定したテストと同様にサーバーを設定し (実行ループを 1 秒ごとにダンプします)、毎回新しい内部プールを排出して確立します。その後、期待される結果が表示されます。

于 2010-03-26T06:45:22.050 に答える