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

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

新規登録して質問してみよう
ただいま回答率
85.35%
MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

Swift

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

Q&A

解決済

1回答

2065閲覧

日本語解析でメモリを大量に消費してしまう

jbe00214

総合スコア63

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

Swift

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

0グッド

0クリップ

投稿2021/07/18 20:46

前提・実現したいこと

swiftやMacosアプリ作成の初心者です。日本語文章を形態素解析してスペース区切りの単語の列に変換する処理をmacアプリで行っております。

発生している問題・エラーメッセージ

少ない文章でサンプル処理をするとうまく動作するのですが,80Mbの文章を対象に処理すると,400kbほど書き込んだところで数十Gbのメモリを消費して,ダウンしてしまいます(メモリがないと言われる)。以下のコードですが,どこに問題があるのでしょうか。もしくは,このようにすると良いというアドバイスをいただければと思います。おわかりになる方,ヒントをください。

該当のソースコード

Swift

1guard let h_src = FileHandle(forReadingAtPath: srcFile) else{ 2 return 3} 4guard let h_res = FileHandle(forWritingAtPath: targetFile) else{ 5 return 6} 7 8/// 内容を読み込む 9let srcContents = h_src.readDataToEndOfFile() 10guard let contentSrcString = String(data: srcContents, encoding: .utf8) else{ 11 return 12} 13///改行文字で区切る 14let sentence = contentSrcString.components(separatedBy: "\n") 15let space = " " 16let spaceData = space.data(using: .utf8)! 17///1行づつ処理 18for sen in sentence { 19 let ans = Tokenizer.tokenize(text: sen) 20 for var item in ans { 21 ///数詞の場合に N に置き換え 22 let predicate = NSPredicate(format: "SELF MATCHES '\\d+'") 23 if predicate.evaluate(with: item) { 24 item = "N" 25 } 26 // String->Dataに変換 27 let itemStr = item.data(using: .utf8)! 28 // Dataを書き込み 29 h_res.write(itemStr) 30 h_res.write(spaceData) 31 } 32} 33h_src.closeFile() 34h_res.closeFile() 35

補足情報(FW/ツールのバージョンなど)

xcode 12.5

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

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

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

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

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

jbe00214

2021/07/19 00:10

早速ありがとうございました。今のところイイ感じです。
jbe00214

2021/07/19 00:26

6%進捗で,300Mbのメモリ使用で推移している。これ以上増えない模様。 うん,たぶん,うまくいきそう。ありがとうございました。ベストアンサーにしたいんですが・・・・
guest

回答1

0

ベストアンサー

Swift 言語では Objective-C と同様に、メモリ管理には参照カウント方式を採用していますが、これに加えて、macOS や iOS の基盤である Foundation フレームワークには、一時的なオブジェクトを取っておくためのオートリリースプールという仕組みがあります。GUI アプリケーションではイベント処理のたびにオートリリースプールが解放されるので、ふだんはあまり気にしなくても良いのですが、大量のデータを処理する場合などは、自分で定期的に解放する必要がある場合があります。
参考: Swiftのメモリ管理 | Swiftの始め方 (Swift 言語の解説なので、オートリリースプールの解説はありません)
参考: オートリリースプールの使い方と基本 : Objective-C プログラミング (Objective-C の記事ですが、基本的な考え方は Swift も共通です)

具体的には、for sen in sentence { の中身を autoreleasepool { 〜 } で囲むと良いでしょう。
参考: 【Swift】Forループの中で重い処理をしたい場合はautoreleasepool{}でメモリ解放。 - 元文系大学生iOSアプリ開発ブログ

diff

1 for sen in sentence { 2+ autoreleasepool { 3 let ans = Tokenizer.tokenize(text: sen) 4 for var item in ans { 5 /// 略 6 } 7+ } 8 }

投稿2021/07/19 01:42

hoshi-takanori

総合スコア7901

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

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

jbe00214

2021/07/19 01:54

ご丁寧に解説いただきましてありがとうございました。処理は先程終了し,すべてうまく期待通りにできました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問