#Unity
#Objective-C
#iPhoneX

iPhoneXの物理メモリ取得で異常な数値(マイナス値)が返ってきた話

More than 1 year has passed since last update.

iPhoneXの物理メモリは、3GBらしい。ということは...

Unityのネイティブプラグインで一部、sysctlを用いてシステム情報を取得する箇所で物理メモリ(RAMが何GBなのか)を取得していた。

ここで、iPhoneXだけがマイナスの数値が返ってきていて、内容が面白かったのでちょっとまとめることに。

物理メモリの取得について

参考にしていた記事があって、[iOS] メモリ情報を取得する件.で紹介されているソースコードをちょっと変更して使っていた。

- (long)hw_phys_mem
{
    long ret = -1;
    long val = 0;
    long err = 0;
    size_t len = sizeof(val);
    long selection[2] = {CTL_HW, HW_PHYSMEM};
    err = sysctl(selection, 2, &val, &len, NULL, 0);
    if(err == 0){
        ret = val;
        return ret;
    }else{
        return ret;
    }
}

Objective-Cでのlongについて

今までのiPhoneに搭載されていたRAMの最大値は、

  • 2GBで2,147,483,648byte

ということで、32byteの型。
iPhoneXのRAMは、

  • 3GBで3,221,225,472byte

だから、そこを想定して

  • int(-2,147,483,648byte ~ 2,147,483,647byte)

ではなく、

  • long(-9,223,372,036,854,775,808byte ~ 9,223,372,036,854,775,807byte)

にしていたはずだったのに...
ちゃんと調べていくと衝撃な事実がありました。

※ちなみに、メモリの取得は、例えば2GBがから2GBちょうどの数値は返ってこない仕様になっていて、1.96GBぐらいの数値が返ってくるようになっているです。

Objective-Cでのlongはいつもと違う...!?

私は、iOSのネイティブ開発をやったことはなく、Unityのネイティブプラグイン開発やXamarinなどで間接的にでしかiOSのアプリ開発に関わっていませんでした。

いろいろ調べてみると、Objective-Cのlongは一般的な64byteの型ではなく、32byteで使用されていると知りました。

なので、longにしたところでintと同じ...というね笑オイ

解決方法

longではなく、unsigned long longで定義すると符号なし64bit整数で対応できたことが今回のオチになります。
Apple公式のsysctlの説明を確認したところ、HW_PHYSMEMをHW_MEMSIZEに変える必要があり、アドバイスをいただき、符号なしを符号ありに戻しました。
また、integerと書かれているのでInt64_tにしました。

- (int64_t)hw_mem_size
{
    int64_t ret = -1;
    int64_t val = 0;
    long err = 0;
    size_t len = sizeof(val);
    long selection[2] = {CTL_HW, HW_MEMSIZE};
    err = sysctl(selection, 2, &val, &len, NULL, 0);
    if(err == 0){
        ret = val;
        return ret;
    }else{
        return ret;
    }
}

 
これでiPhoneXの物理メモリ(RAM)の数値が正常に取れました。
取れた数値は、2,920,284,160byteで2.72GB、約3GBということになっているっぽい。

(余談) sysctlの返り値がintなのだが

公式記事で解説されているsysctlを確認すると、受け取っている型がint固定っぽかったので、sysctlの他でも端末情報を取得する手段を探していたところ、NSProcessInfoでも物理メモリが取得できることがわかりました。

まぁ、今回は大きな改修なく、変数と返り値の型を変えてあげるだけでなんとかなったんでNSProcessInfoにはしなかった感じです。

まとめ

今回は、オーバーフローで型問題が原因でしたが、、、まさかlongが32byte判定とは思いもしませんでした笑汗

確認するとき、Objectvie-Cを書き換えてビルドして→iPhoneXにアプリ入れて→確認して→失敗したらやり直し...の繰り返し。やっぱしネイティブプラグインを作ったり直すときって結構ツライですよねぇ^^;