1

Objective-C++ クラスでオブジェクトを作成すると、動作に違いが見られます。

DictionaryWith と numberWith を使用してNSDictionary包含オブジェクトを作成すると、オブジェクトが解放されることはありません。NSNumberと を使用してそれらを作成するallocinitWith、問題なくクリーンアップされます。

これは、同じプロジェクトの Objective-C クラスでは見られません。プロジェクトで ARC が有効になっています。CFNumberXcode 4.5.2 で Allocations プロファイリング ツールを使用して、と __の "# Living" 値を調べていNSDictionarylます。

// These objects will NOT be released.
NSDictionary* dict1 = [NSDictionary dictionaryWithObjectsAndKeys:
  [NSNumber numberWithUnsignedInt:val1], @"val1",
  [NSNumber numberWithUnsignedInt:val2], @"val2",
  [NSNumber numberWithUnsignedInt:val3], @"val3",
  nil];    
dispatch_async(dispatch_get_main_queue(), ^{
  [[NSNotificationCenter defaultCenter]
  postNotificationName:KEY_NET_STATS_VIEW_UDATE object:nil userInfo:dict1];
});

// These objects *will* be released.
NSDictionary* dict2 = [[NSDictionary alloc] initWithObjectsAndKeys:
  [[NSNumber alloc] initWithUnsignedInt:val1], @"val1",
  [[NSNumber alloc] initWithUnsignedInt:val2], @"val2",
  [[NSNumber alloc] initWithUnsignedInt:val3], @"val3",
  nil];    
dispatch_async(dispatch_get_main_queue(), ^{
  [[NSNotificationCenter defaultCenter]
  postNotificationName:KEY_NET_STATS_VIEW_UDATE object:nil userInfo:dict2];
});

alloc/initWith を使用してコードを記述しても問題はありませんが、その違いの理由を理解したいと思います。私が読んだものはすべて、ARCの下で同等であるべきだと言っています。

このコードが呼び出されたときのスタック トレース。以下はすべて C++ です。

#0  0x001fbbe4 in ItRtpSessionManageriOS::OnItRtpOutgoingStatsUpdate(ItRtpSession&, ItRtpSessionManager::ItRtpStats const&)  
#1  0x0007018a in CSceApp::OnItRtpOutgoingStatsUpdate(ItRtpSession&, ItRtpSessionManager::ItRtpStats const&)  
#2  0x0006b808 in ItRtpSession::CallStatsUpdateCallback(ItRtpSessionManager::ItRtpStats const&)  
#3  0x0006ab1e in ItRtpSessionSharedCommXYZ::UpdateOutgoingStats(unsigned long, unsigned long)  
#4  0x0006a958 in ItRtpSessionSharedCommXYZ::Update(unsigned int, unsigned int)  
#5  0x000764ca in CSceApp::EvTimerServiceMgrAwaken(bool, unsigned int, void*)  
#6  0x00076908 in non-virtual thunk to CSceApp::EvTimerServiceMgrAwaken(bool, unsigned int, void*)  
#7  0x002a0134 in xyz::CServicingThread::Activate(unsigned long long, bool*)   
#8  0x0029fb98 in xyz::CServicingThread::Behavior()  
#9  0x0029fc34 in non-virtual thunk to xyz::CServicingThread::Behavior()  
#10 0x002578de in xyz::CAliveObj::StartMechanism(void*)  
#11 0x00259f9e in xyz::CThread::ThreadEntry(void*)  
#12 0x348b5310 in _pthread_start ()  
#13 0x348b51d8 in thread_start ()  
4

2 に答える 2

2

ARC では、autorelease プールを利用するための 2 つのメカニズムがあります。実行ループの一部として、@autoreleasepool を使用してスコープに結び付けられます。プールは、最初のケースでは runloop の最後に、または 2 番目のケースでは自動解放プールが範囲外になったときにのみ排出されます。

したがって、runloop を実行させない場合、そこに置いたものはすべて排出されません。同様に、どこかで @autoreleasepool を使用しているが、そのスコープを終了していない場合 (おそらくどこかでタイトなループに陥っているか、スコープ内でブロックしている可能性があります)、プールのドレインは表示されません。

それを考えると、コードを見て、それが起こっているかどうかを確認する必要があります。残念ながら、コードをさらに投稿しない限り、問題を特定するお手伝いをすることはできません。

于 2012-12-19T00:27:29.470 に答える
1

init...ARC でメソッドを使用するreleaseと、コンパイル時にそのオブジェクトへの最後の参照の後に呼び出しが挿入されます。初期化後にそのブロックで参照しない場合dict2、以下のコードのようにコンパイルされます。

NSNumber *n1 = [[NSNumber alloc] initWithUnsignedInt:val1];
NSNumber *n2 = [[NSNumber alloc] initWithUnsignedInt:val2];
NSNumber *n3 = [[NSNumber alloc] initWithUnsignedInt:val3];
NSDictionary* dict2 = [[NSDictionary alloc] initWithObjectsAndKeys:
  n1, @"val1",
  n2, @"val2",
  n3, @"val3",
  nil];
[n1 release];
[n2 release];
[n3 release];
[dict2 release];

(保持したい場合は、それへの強い参照を保持する必要があります)

対照的に、 のようなクラス メソッドを使用すると、dictionaryWithObjectsAndKeys:(通常) 自動解放されたオブジェクトが取得されます。実行ループの最後に解放されます。自動解放された辞書を作成した直後にログに記録すると、それはまだ存在し、有効です。

于 2012-12-18T23:48:43.473 に答える