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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

2回答

5635閲覧

作成したスレッドのメモリの解放タイミングについて

keione

総合スコア1

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

1クリップ

投稿2021/10/03 18:41

前提・実現したいこと

スレッド作成によって取得されたメモリ(スタック領域?)がどのタイミングで解放されるか、ご教示いただきたいです。

当初以下の①のパターンを想定しておりましたが、実機確認すると➁のパターンのように見えております。

①スレッド終了後、その他のプログラムからも使用できるメモリとして解放される(PTHREAD_CREATE_JOINABLEの場合は、pthread_join()実行後)
➁スレッド終了後、プロセス内で再利用できるメモリとして解放される。プロセスが使用するメモリ領域として確保しているため、その他のプログラムから使用できない。プロセス終了後、スレッドで取得した領域含め解放される。

ググってみましたが、スレッドのメモリ解放とは、プロセス内での再利用可能メモリを指すのか、その他のプログラムからも使用できるメモリとして解放されることを指すのかわかりませんでした。

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

スレッドを6つ同時に作成し終了する、その後2つ同時にスレッドを作成し終了するプラグラムで検証した結果が以下となります。
スレッドが終了するとメモリが再利用可能になるため、スレッド解放後にメモリ使用率が下がることを期待しましたが、スレッドが終了してもメモリの解放が行われませんでした。

タイミング  :VSZ :RSS メインキック :2516 :620   6スレッド作成:117360:620   6スレッド解放:166504:1124:ここでメモリが解放され、RSS,VSZが下がると思っていた 2スレッド作成:166504:1124:値の増加なし 前の6スレッドで取得したメモリをプロセス内で再利用? 2スレッド解放:166504:1124   終了     :166504:1124:最後までスレッドで取得したメモリをプロセスとして解放せず終了

該当のソースコード

clang

1#include <stdio.h> 2#include <unistd.h> 3#include <pthread.h> 4 5//スレッド 6void *func_null(void *arg){ 7 char test[102400]; 8 printf("new thread created : %ld \n", pthread_self()); 9 sleep(5); 10 printf("thread exit\n"); 11 pthread_exit(): 12} 13 14 15int main() 16{ 17 pthread_t th_cli1; 18 pthread_t th_cli2; 19 pthread_t th_cli3; 20 pthread_t th_cli4; 21 pthread_t th_cli5; 22 pthread_t th_cli6; 23 pthread_t th_cli7; 24 pthread_t th_cli8; 25 26 pthread_attr_t th_cli_attr; 27 int status; 28 29 // スレッド属性 30 pthread_attr_init(&th_cli_attr); 31 pthread_attr_setstacksize(&th_cli_attr, 204800); 32 pthread_attr_setdetachstate(&th_cli_attr,PTHREAD_CREATE_DETACHED); 33 sleep(10); 34 35 //スレッドを6個作成 36 status = pthread_create(&th_cli1,&th_cli_attr,func_null,NULL); 37 status = pthread_create(&th_cli2,&th_cli_attr,func_null,NULL); 38 status = pthread_create(&th_cli3,&th_cli_attr,func_null,NULL); 39 status = pthread_create(&th_cli4,&th_cli_attr,func_null,NULL); 40 status = pthread_create(&th_cli5,&th_cli_attr,func_null,NULL); 41 status = pthread_create(&th_cli6,&th_cli_attr,func_null,NULL); 42 43 printf("6 thread finished\n"); 44 sleep(15); 45 46 //スレッドを2個作成 47 status = pthread_create(&th_cli7,&th_cli_attr,func_null,NULL); 48 status = pthread_create(&th_cli8,&th_cli_attr,func_null,NULL); 49 50 sleep(10); 51 printf("th_cli1 : %ld\n", th_cli1); 52 printf("th_cli2 : %ld\n", th_cli2); 53 printf("th_cli3 : %ld\n", th_cli3); 54 printf("th_cli4 : %ld\n", th_cli4); 55 printf("th_cli5 : %ld\n", th_cli5); 56 printf("th_cli6 : %ld\n", th_cli6); 57 printf("th_cli7 : %ld\n", th_cli7); 58 printf("th_cli8 : %ld\n", th_cli8); 59 printf("exit\n"); 60 sleep(10); 61 return(0); 62}

試したこと

PTHREAD_CREATE_DETACHEDだけでなくPTHREAD_CREATE_JOINABLEでも試してみましたが、概ね同じような値が確認できました。

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

Ubuntu 20.04.3 LTS(VMware Workstation 15上で動かしています)
CPUは8コアで設定しています。

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

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

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

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

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

guest

回答2

0

ベストアンサー

まず、今回のような単純なサンプルでメモリ増加・減少を追うのは難しいと思います。

1つには、スレッド生成時のスタックの確保が mmap、消滅時の解放が munmap なので増減は確かにあるのですが、glibc の実装としてある程度「一旦確保したスレッド用スタックはキャッシュする」という挙動があるためです。
新しい ( 2.34以降?の ) glibc だと、チューニングパラメータ glibc.pthread.stack_cache_size が設けられているのでこの挙動は明らかになってますが、どうやらこのパラメータがない時代から、キャッシュする挙動自体はあるようです。
※ Ubuntu18/WSL1(Win10) の glibc 2.27 で確認

もう1つは、標準ライブラリである malloc が、定常状態に落ち着くまでメモリをそれなりに確保し続けるという点です。特にマルチスレッドの場合、スレッド毎の競合を避けるためアリーナという単位で kernel からメモリを結構確保します。
※しかもプログラマが明示的にで malloc を使っていなくても、様々な標準ライブラリの裏で malloc は使われます。
これのせいで、スレッド絡みのメモリ増減の値が隠れてしまいます。

なのでせめて観測したいのであれば、

  • スレッドのスタックサイズを大きく、スレッド数を多くしてキャッシュの影響を相対的に小さくする
  • malloc絡みのチューニングパラメータを調整して、アリーナの確保を抑制する。
    ( おそらく環境変数 MALLOC_ARENA_MAX が一番影響が大きい )

といった対処が必要かと思います。

投稿2021/10/12 16:56

編集2021/10/12 16:59
angel_p_57

総合スコア1681

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

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

keione

2021/10/24 09:58

現在のプログラムでは検証自体難しいこと理解しました。 mallocやアリーナの仕様について調べてから再度検証しようと思います。
guest

0

Linuxでは、仮想空間を管理する単位はプロセスです。そして、プロセスの使用する仮想アドレス空間は、exec系のシステムコールを実行しない限り増加することはあっても減少することはありません。
仮想アドレス空間が増加するのは、brk/sbrkあるいはmmapというシステムコールが実行された場合です。

メモリ管理、アドレス空間、ページテーブル あたりを読まれるのが良いかと思います。

スレッドは、プロセスの仮想空間内で動いています。スレッドが終了してスタックを解放しても、プロセスの仮想空間は減少しませんので、②となります。

投稿2021/10/03 21:11

編集2021/10/03 21:20
ppaul

総合スコア24670

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

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

keione

2021/10/09 00:21

Linuxでは、仮想空間を管理する単位はプロセスです。そして、プロセスの使用する仮想アドレス空間は、exec系のシステムコールを実行しない限り増加することはあっても減少することはありません。 ⇒exec系のシステムコールにmunmap()は入りますでしょうか munmap()で仮想アドレスの解放が確認できました。 仮想アドレス空間が増加するのは、brk/sbrkあるいはmmapというシステムコールが実行された場合です。 ⇒認識相違ないです スレッド作成のプログラムでもmmapが発行されていました。 メモリ管理、アドレス空間、ページテーブル あたりを読まれるのが良いかと思います。 ⇒拝読しましたが、スレッドが「メモリを解放する」という表現で私が確認したい点について解消できませんでした… スレッドは、プロセスの仮想空間内で動いています。 スレッドが終了してスタックを解放しても、プロセスの仮想空間は減少しませんので、②となります。 ⇒一度プロセスが取得した仮想メモリはmunmap()などで明示的に解放しない限り、解放されない スレッドのメモリの解放とはプロセス内で仮想メモリ(≒に割り当てられる実メモリ)を再利用することを指す 上記の通り理解しました 誤りがございましたらご指摘ください
angel_p_57

2021/10/12 16:42

> exec系のシステムコールを実行しない限り増加することはあっても減少することはありません。 その後に書いてある mmap, brk で増加するのだから、その逆の munmap, brk(減らす方) で減少します。「exec直後からの減少」を意図しているのであればまだ分からなくもないですが、スレッド生成・消滅時の話として不適切です。 > スレッドは、プロセスの仮想空間内で動いています。スレッドが終了してスタックを解放しても、プロセスの仮想空間は減少しません 実装依存なのであまり追及したくはないですが、glibcではスレッドのスタックは mmap で確保されます。ですので当然、スレッド消滅時 munmap で解放されれば仮想空間としても減少します。 おそれながら ppaul氏は調べずに想像で書いているのではないでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問