Github上にバックエンドエンジニア採用時の質問に使える題材としてまとめられているページがある。コンピュータアーキテクチャ、デザインパターン、DB、Web、分散システム、チームマネジメントなど多種多様な題材がある。
解答はGithub上には一切書かれていない。正解や不正解がない問いがあること、この質問が会話のきっかけとなり、面接を受けている者のレベルを把握できることを期待していることなどが書かれていた。実務経験がある方なら経験や知識を活かす。未経験なら自分で調べつつ考えてほしいということだと思う。
この記事ではそのうちの1つについて調べたことをまとめた。
質問
原文:Globals Are Evil
Why are global and static objects evil? Can you show it with a code example?
内容:なぜグローバル変数が悪なのか?
なぜグローバル変数・静的変数が悪なのか?
コードサンプルを使って説明できますか?
※問題の訳や意図の解釈が間違っている可能性があります。
解答
メモリ領域
解答に必要と思われる前提知識としてメモリ領域について調べた。
メモリ領域の説明はC言語やC++言語の解説で紹介している記事も多かったので、場合によっては名称や扱われ方が異なるかもしれない。
コンピュータが処理をする時、計算結果や計算対象を覚えておく必要がある。
これらはメモリ上に記録され、アドレスを指定することでメモリ上に覚えておきたいデータを書き込んだり読みだしたりする。CPUによって制御される。
そのメモリにはいくつかの領域がある
・テキスト領域
・静的領域
・ヒープ領域
・スタック領域
テキスト領域
テキスト領域は、プログラム内の命令部分が保存される。
機械語に翻訳されたプログラムが格納される。
機械語が実行されることでプログラムが動く。
プログラムが機械語に翻訳されるのはコンパイラの働きによるもの。
プログラムが変わることはないので、テキスト領域で記憶されている内容は変化することはない。
※自分自身を書き換えるプログラムがあるそうで、そのうち調べたい。
静的領域
グローバル変数などの静的変数が保存される。
プログラムのどこからでも読み出しや書き込みができる。
ヒープ領域
メモリを動的に確保するときに保存される。
プログラマが自分でメモリを開放しなければならない。
Pythonではガベージコレクションがあるので、自動的に開放してくれる。
ガベージコレクションは時折予期しない動作をする場合があることや、解放されないまま放置される部分がある。それらが積み重なるとメモリリークが発生する。
覚えておきたい内容をメモリ上のどこに保存するかを指定するためにアドレスが使われるが、
ヒープ領域でのメモリ確保はアドレスの低い方から行われる。
スタック領域
ローカル変数などが保存される。
スタック領域でのメモリ確保は、アドレスの高い方から行われる。
ヒープ領域はアドレスの低い方から確保するので、アドレスの高い方はまだ空いている可能性がある。
スタック領域はアドレスの高い方から確保していくことで、スタック領域で確保できる分を越えるほどにローカル変数が多くなった場合でも、ヒープ領域にまで広げてメモリを確保していくことができる。
グローバル変数を使わない方が良いとされる理由
プログラムが複雑になる
グローバル変数はプログラム内のどこからでも読み出しができるので便利な反面、プログラムのどこからでも書き換えることができる。
いつどこでグローバル変数が書き換えたかがわからなくなることがあり、
プログラムの処理の流れを追うことが難しくなる。
そうなると、想定外の動作が発生したときにその原因を特定することができなくなる。
また、プログラム内のどこからでもグローバル変数にアクセスすることができるので、プログラマがコードを書き換えたときにどこにどのような影響がでるのか把握しづらい点もある。
スレッドセーフではなくなる
グローバル変数は複数のスレッドから同時にアクセスされる可能性があり、スレッドセーフではない。
マルチタスク・マルチスレッドについて
要追記
スレッドセーフについて
要追記
テストが困難になる
グローバル変数を多用すると、プログラムを単体でテストすることが困難になる。
関数A内でグローバル変数を使っているが、そのグローバル変数は関数Bによって書き換えられた後の状態であることが前提になっている。みたいな状況だと、関数Aだけを単体でテストすることが難しいのかなと想像した。
どうすれば良いのか?
グローバル変数は使わず、関数を作った時に引数として必要なものを受け渡しするようにコードを書いていくのが良いという話が多い。
グローバル変数を使わないコーディングができるのか?
グローバル変数を全く使わずにコードを書くことはできるのかと言う話を見つけたので読んでいると以下のような指摘があった。
・全ての情報を引数でやりとりするので引数の数が多くなる
・ある関数では本来必要のない情報まで持ってしまう
・バケツリレーのように関数同士で引数を受け渡しすることになる
設定やセッション情報など、プログラム中で変わることがない情報については、グローバル変数が良いといった話もあった。
一般的にグローバル変数は使わない方が良いとされているものの、
メリットデメリットがあるので状況に応じて使い分けしていく必要があるのだと思う。
補足・参考・メモ
・メモ
冒頭で紹介したページ
・参考
ヒープ領域とスタック領域のメモリレイアウト – wake-mob.jp (わけモブ)
マルチプロセス(マルチタスク)とマルチスレッドの違いを解説(IT素人さん向け) – wake-mob.jp (わけモブ)
SMTの基本理解 – 同時マルチスレッディング – Qiita
イケてるエンジニアになろうシリーズ 〜メモリとプロセスとスレッド編〜 – もろず blog (hatenablog.com)
コメント