質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1878閲覧

realm登録処理で使用メモリが増え続ける

umeme1011

総合スコア16

Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2019/08/26 17:46

編集2019/08/26 17:55

いつもお世話になっております。
swift初心者です。

Xcode 10.2.1
swift 5
realm
で某ゲームのスコア管理アプリを勉強がてら作っています。

問題

realmへの保存の処理で、メモリが増え続け困っています。
約7000件のデータ登録で使用メモリが2Gを超えてしまいます。

処理内容

・アカウント毎にスレッドを立て
HTMLをスクレイピング→バージョン(という単位)毎にrealmに保存
を行っています。
(約1200件×6アカウント)

・上記のスレッドをDispatchGroupでまとめています。

調査したこと

・realm登録処理以外ではメモリ使用量がさほど増えないことは確認しています。

・realmのscoreオブジェクトが件数毎に増えていっているのが原因なのでは・・と思っています。
イメージ説明

ソース

アカウント数分 toRivalScore をループしています。

func toRivalScore(iidxId: String) { print("toRivalScore Strat") dispatchGroup.enter() // ライバルスコア取り込みスレッド // アカウント毎に1スレッド // バージョン毎にDB保存 dispatchQueue.async(group: dispatchGroup) { print("toRivalScore Thread Start") print("取り込み対象アカウント" ,iidxId) // スコア用realm let documentDir: NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString let scoreRealmPath: String = documentDir.appendingPathComponent("(Const.Realm.scoreFileName).realm") guard let scoreRealm: Realm = try? Realm(fileURL: URL(fileURLWithPath: scoreRealmPath)) else { print("scoreRealm 生成失敗") self.stopFlg = true return } let playStyle: Int = self.myUserDefaults.getPlayStyle() // 対象アカウントスコアデータ全件削除 let result = self.myRealm.getScoreByPlayStyleAndIidxId(playStyle: playStyle, iidxId: iidxId) try? scoreRealm.write { if !result.isEmpty { scoreRealm.delete(result) } } // バージョン数分ループ let versions: Results<Version> = self.myRealm.getAllVersions() for i in 0 ..< versions.count - 1 { let rival: Rival = self.myRealm.getRivalByPlayStyleAndIidxId(playStyle: playStyle , iidxId: iidxId).first ?? Rival() let code: String = rival.code ?? "" // HTML取得 let data: NSData = self.common.postRequest(dataUrl: Const.Url.scoreSeriesRival , postStr: "list=(i)&play_style=(String(describing: playStyle))&s=1&rival=(code)" , cookieStr: self.listVC.cookieStr) // 進捗更新用 var versionName: String = versions[i+1].name ?? "" if i == 0 { versionName = (versions[i].name ?? "") + "&" + versionName } let djName: String = rival.djName ?? "" // HTMLスクレイピング let scoreArray: [Score] = self.parseScorePerVersion(html: String(data: data as Data, encoding: .windows31j) ?? "" , isMyself: false, iidxId: iidxId, djName: djName, versionName: versionName) if self.stopFlg { break } // DB保存 self.saveRivalScore(iidxId: iidxId, scoreArray: scoreArray , scoreRealm: scoreRealm, scoreRealmPath: scoreRealmPath) } self.dispatchGroup.leave() print("toRivalScore Thread End") } print("toRivalScore Strat") } // スコアページHTMLパース func parseScorePerVersion(html: String, isMyself: Bool, iidxId: String , djName: String, versionName: String) -> [Score] { print("parseScorePerVersion Start") var scoreArray: [Score] = [Score]() 〜〜〜 省略 〜〜〜 let score: Score = Score() 〜〜〜 省略(スクレイピングしてscoreモデルに格納しています) 〜〜〜 // scores配列に追加 scoreArray.append(score) } } } print("parseScorePerVersion End") return scoreArray } // Score TBL 保存(ライバル) func saveRivalScore(iidxId: String, scoreArray: [Score], scoreRealm: Realm, scoreRealmPath: String) { print("saveRivalScore Start") try? scoreRealm.write { let now: Date = Date() for score in scoreArray { score.createDate = now score.createUser = Const.Realm.SYSTEM score.updateDate = now score.updateUser = Const.Realm.SYSTEM score.save(scoreRealmPath: scoreRealmPath) } } print("saveRivalScore End") }

その他、お気づきの点ありましたらご指摘いただけると幸いです。 

どうぞよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

実行環境がないのであくまで調べる方法でこんなものがありますよという情報だけ提供します。

xcodeにはメモリリークを調べるツールが付属しています。
参考:
XcodeのInstrumentsを使ったiphoneアプリのメモリリーク対策
https://kerubito.net/technology/3298
(私は使い方は忘れましたが)

メモリが増えた状態でどんなオブジェクトが増えているかを見たりすることで、原因の予測が付く場合があります。
例えば、その時点でオブジェクトは存在しないはずなのに、残り続けているものがあればビンゴです。
(わからない場合もあります。あとキャッシュ機構等で意図的に残っている場合もあるので一概には言えません。)

よくあるのが、オブジェクト同士の相互参照でメモリが開放されずに残り続けてしまうことです。
この辺は片方を弱参照にすることで解決できます。

調べてみてください。

投稿2019/08/27 00:22

takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

umeme1011

2019/08/27 04:28

ご回答ありがとうございます。 ご教授頂いた、Instrumentsで調査してみたところ realmのRLMStringDataToNSStringあたりでリークしているようでしたので 検索してみたところ、以下が当てはまりそうな気がしました。 https://github.com/realm/realm-cocoa/issues/6147 とりあえず、realmから取得したデータをグローバル変数に格納することをやめてみます。 結果の方はまたご報告いたします。
umeme1011

2019/08/29 01:50

上記を試してましたが変わらずでした。。 そもそも初心者なのに色々作り込み混乱してきたので、 もとのアプリをプロトタイプとしてよりシンプルに一から作り直すことにしました。 リークチェックしながら作ってみます。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問