Странности памяти устройства iPhone / симулятора с помощью Objective-C ++ - PullRequest
3 голосов
/ 10 ноября 2009

Я портирую проект на iPhone (из Windows Mobile) и делюсь большей частью общего кода C и C ++, насколько это возможно, используя Objective-C ++. Однако во время тестирования я наткнулся на любопытную и неприятную проблему, которая проявляется только при работе на устройстве. Я добавил код проблемы в новый проект, чтобы доказать воспроизводимость и облегчить совместное использование.

// MemoryTestAppDelegate.mm
#include "MemoryTestAppDelegate.h"
#include "Widget.h"

@implementation MemoryTestAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching: (UIApplication*)application {
    Widget widget;
    const wchar_t wideHello[] = L"Hello, world!";
    const char narrowHello[] = "Hello, world!";
    widget.Go();
    widget.Go(wideHello);

    [window makeKeyAndVisible];
}

- (void)dealloc {
    [window release];
    [super dealloc];
}

@end

// MemoryTestAppDelegate.h
#import <UIKit/UIKit.h>

@interface MemoryTestAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow* window;
}

@property (nonatomic, retain) IBOutlet UIWindow* window;

@end

// Widget.h
#include <iostream>

class Widget {
public:
    Widget() { };
    ~Widget() { };

    void Go() const { std::wcout << L"Widget is GO." << std::endl; };
    void Go(const wchar_t* message) const { std::wcout << message << std::endl; };
};

// main.mm
#import <UIKit/UIKit.h>

int main(int argc, char* argv[]) {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"MemoryTestAppDelegate");
    [pool release];
    return retVal;
}

Остальные файлы проекта, а также настройки по умолчанию предоставляются при создании нового приложения для iPhone на базе Windows. (Я удалил Interface Builder, удалив файл .xib, удалив «Основное имя файла основного пера» из MemoryTest-Info.plist и указав @ «MemoryTestAppDelegate» в качестве 4-го параметра для UIApplicationMain в main.mm.)

Симулятор запускает этот пример, как и ожидалось, но устройство представляет мою проблему: пошагово просматривая код в applicationDidFinishLaunching, объект Widget создается, как и ожидалось. Тем не менее, WideHello и thinHello оба, кажется, повреждены в области наблюдения местных жителей. (wideHello не отображается, но указывается правильное количество символов, а smallHello отображается как "` K3 \ x10f \ x11 ".) Изучая две строки в окне памяти, отображается правильное содержимое - 64 байта за пределами предполагаемого адреса из широкого Привет и узкого Привет.

Как показывает второй вызов перегруженного метода, Widget :: Go (const wchar_t *) const, строка wideHello отображается через std :: wcout, и после перехода через applicationDidFinishLaunching строка выводится правильно! Тем не менее, операции копирования с использованием wcscpy / memcpy читают из «предварительных» данных на 64 байта раньше фактического содержимого, что вызывает много проблем для моего приложения на реальном устройстве. Если я заменим инициализацию виджета в локальном стеке на виджет * и динамическое выделение, расположение памяти будет таким, как ожидалось. Я пробовал другие варианты, но только объекты C ++, выделенные в стеке, похоже, вызывают проблему.

Любая информация будет принята с благодарностью, спасибо за чтение.

1 Ответ

1 голос
/ 16 февраля 2010

Даже Apple сама признала, что между их симулятором и устройством есть некоторые различия.

К сожалению, я не могу помочь вам с вашей проблемой, однако имейте в виду, что код симулятора компилируется и запускается буквально на процессоре вашего Mac, например, компилируется и работает на вашей архитектуре Intel, i386, а когда вы компилируете для устройства, оно совершенно иное, компиляция для использования armv6 устройства.

Любые обнаруженные вами причуды, которые звучат так, как будто это проблемы с архитектурой i386, вероятно, никогда не появятся на устройстве, и наоборот.

...