C言語とBCCでDLLを作っています。
どこかのページで「DLLではstatic変数やグローバル変数を使わないほうがいい」と読んだ記憶があるのですが、それではDLLが呼び出されてから開放されるまでずっと保持し続けたい内容がある場合、どのようにすればよいのでしょうか?
いちいち malloc() や realloc() 等で管理する必要があるのでしょうか?
よろしくお願いします。
>「DLLではstatic変数やグローバル変数を使わないほうがいい」
その不明確な情報の出所を探したほうがいいと思います。
特定条件があって、使わないほうがいいとなっていると思うのですが
使わない方法で、値を保持するのは、共有メモリ使うとかするのかな
けど、面倒そうですね
DLLのグローバル変数で問題になった経験が1つあります。
明示的なDLLの呼び出しを用いて複数のDLLを用いていたアプリで、
アプリを使用中に現在使用していないDLLがアンロードされ、
再度そのDLLを使用した場合、グローバル変数などの情報が初期化されていたという経験があります。
結構大きなプロジェクトで、全体的な仕組みを十分に理解しておらず、
明示的なDLLの呼び出し部分(解放部分)などがどうなっているかよくわかっていませんが、
これで一度痛い目にあいました。
参考までに。
>その不明確な情報の出所を探したほうがいいと思います。
カンなのですが、MFCのマルチスレッドがらみのWebだったと思います。
>特定条件があって、使わないほうがいいとなっていると思うのですが
と、言うことは、とりあえずは使っても差し支えないという意味でとっていいのでしょうか?
KING・王さんのおっしゃることに関して思ったのですが、どうも呼び出し側アプリの問題なのではありませんか?
私が問題になったアプリは、結構大きなアプリで、大きくいくつかの機能に分かれています。
仮に機能Aと機能Bと有った場合に、それぞれ機能単位でDLL化を行っており、
機能Aを使用中には、機能BのDLLをロードする必要がないので、機能BのDLLは、
メモリにロードされていない状態になっています。
ここで、機能AのA2という処理まで行った状態で機能Bに切り換えた場合に、
メモリ容量の関係で、機能AのDLLがアンロードされてしまうことがあったのです。
機能Bに切り換えた後に、機能Aに切り換えたところ、
A2の処理から復帰できることを期待していたのですが、
A2の処理に使用するため情報を機能AのDLLのグローバル変数として保持していたのですが、
一度アンロードされていたため、保持していた情報が失われて、バグとなってしましました。
(あまり上手く説明できなくて申し訳ございません。)
ここでなぜ機能AのDLLがアンロードまでされるかというと、
恐らく私の問題にしているアプリは、組込み環境でのアプリで、
メモリ搭載量に制限があり、またストレージの耐久性の問題等から、
メモリのスワップを行わないという環境でした。
よって、大きなアプリを使用すると、物理メモリに不足が発生するような状況が
容易に発生し、そのためDLL単位でのアンロードが発生していたと思われます。
今のPCでは、基本的にスワップが行えるので、このような状況はありえないのかもしれませんが、
組込み環境などではまだまだ物理メモリの容量も制限されますし、
HDDは信頼性の問題で、実装できないということもありますし。。。
昔のPCのゲームなどでは、数十KBのメモリと数百KBのディスク内で、
このようなスワップのようなこともそれぞれのプログラムで実装などしていたのには、
非常に感心させられます。。。
(PC88のウィザードリーなどでは、キャンプから抜けるときに発生する、
スワップの処理中にコーヒーが飲めるぐらい時間(数分)がかかりましたが。。。)
最後の方は、無駄話になってしまったような気もしますが、お許しください。
Cのみでプログラムを作るなら、グローバル変数がないと話にならない。
C++を使うなら、"極力グローバルは使わない。"はオブジェクト指向の考え方に
基づいています。
MFCはC++のライブラリですから、グローバルは推奨しません。
(dll以前の問題です。)
でも使ってはいけないという事ではなく、使わなければならない時は
使います。
MFCでdllを作ってもCWinApp派生のクラスを1つtheAppという名前で
もっていたりします。
呼び出されてから開放されるまでずっと保持し続けたい内容がある場合は
別にグローバルにしてもいいと思います。
(その事で発生し得る問題を考えなくてはなりませんが。)
また、マルチスレッドがらみになると、話は全然別です。
自分で確保したメモリは(たとえDLLがアンロードされても)自分で解放するまで内容は消えないのですよね?
解決しました。
やはり自分で確保して、使い終わったら解放するようにします。
ありがとうございました。
ツイート | ![]() |