質問者
VC6.0からVC8.0への移行で、モジュールロードが性能劣化する。改善策は?

質問
-
私(達)が開発しているシステムのIDEを、Visual Studio 6.0から、VC8.0(Visual Studio 2005)へ変更したことにより、システムの性能劣化が発生しました。
原因はモジュールロードの遅延によるものと判断し、いくつかの対策を講じましたが、解消できていません。特に、バッチファイルから複数のExeを起動する機能で、顕著に性能劣化しています。
以下に記した対策により、性能劣化を改善できることが判りましたが、システム全体での対応ができないため、採用できていません。
これら以外の方法で、モジュールロードの高速化、またはExe起動の高速化を行う方法をご存知でしたら、教えて頂けないでしょうか?■開発環境
OS :WindowsXP SP3
IDE :Microsoft Visual Studio 2005 Professional Edition SP1
使用言語:C/C++■実行環境
OS :WindowsXP SP3■システム規模
モジュール数(ExeとDLL) 4000以上■状況
測定により、Exe1つあたりの起動で、約1秒の劣化が発生していることが判明。(リンクしているDLLの数で差異がある模様)
このため、バッチファイルから複数のExeを起動する機能では、VC6.0時代12秒程度だったものが、VC8.0で25秒以上かかるようになりました。
Exeの起動以外でも性能劣化はありますが、その部分の劣化の割合が少ないため、改善効果は少ないです。■対策
1.ランタイムライブラリをスタティックリンクに変更
コンパイルオプション(コード生成:ランタイムライブラリ)を、「マルチスレッド (/MT)」に変更することにより改善できることが判明したが、この場合、システム全体のコンパイルオプションを変更する必要がある。
当システムではコンパイルオプションの変更ができないモジュールがあるため採用できない。
2.モジュールローダーの高速化
リンクするDLLに、ベースアドレスを設定することにより改善できることが判明したが、システム全体のDLLに対しベースアドレスを設定することが困難である。また、今後Windows7へ移行するため、Win7に搭載されているアドレス空間配置のランダム化(ASLR)により、ベースアドレスの設定は無効になると考えている。
このため、採用できていない。以上、同様の現象に対処した方がいましたら、解決策を教えて頂けないでしょうか?
宜しくお願いします。
すべての返信
-
XP環境で、ベースアドレスを適切に指定すると読み込みが高速化されるのでしょうか?(2.のところ) そしてそれはWindows 7では効果あるのでしょうか、ないのでしょうか? 更には、従来のVC6のバイナリをWindows 7で動作させた場合の読み込み速度はどうなのでしょうか?
この辺りの兼ね合いで、Vista以降を意識して/DYNAMICBASEを指定しつつ、XPでの読み込み速度を意識して/BASEを指定することになるのではと思います。別のアプローチとしてリンカによるDLLの遅延読み込み は効果ありますでしょうか?
…ところでファイル数多すぎませんか?
- 回答の候補に設定 山本春海 2010年8月4日 9:07
-
これだけのモジュール数でシステム作っている人(経験者)が少ないと予想される中で、さらに同じ現象にあたって解決策を持っている人は皆無かもしれません。
また、「システム全体の設定を変更するものは採用できない」だと手を打てないことと同義ですが、本当にできないのでしょうか。
全体を統一することができなくても、部分的に外してやることで、全体としては短縮できるかもしれないということはないのですか。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。 -
佐祐理様、回答ありがとうございます。
ご指摘頂いた箇所については、まだ調査が足りていない部分があると思いますが、現段階では対応が難しそうなので、対策の候補から外しています。
やっぱり、VS2005で、なぜモジュールロードが遅くなったのか、これが解かっていないのが問題なんですよね。
これが解かっていないから、ハッキリした対策が打てていない。
小手先の策をやってはいますが、大した改善はないです。ところで、教えて頂いたDLLの遅延読み込みによる性能改善を検証してみようと思いますが、これによる改善理由は何でしょうか?
リンクしているDLLのうち、関数を呼び出さないものがある場合に有効なのでしょうか?
「リンカによる DLL の遅延読み込み」の説明を読んでも、イマイチ改善理由がピンと来ないです。すみませんが、宜しくお願いします。
> …ところでファイル数多すぎませんか?
詳しいことは書けませんが、このシステムの特色で、古いバージョンのものも動作するようにしているためです。宜しくお願いします。
-
モジュール数 4000という数字がどれほどの意味を持っているのか理解されていますでしょうか? 手元のWindows 7の C:\Windows\System32 ディレクトリで 2700 でした。極端な言い方ですが、Windowsよりも大きなシステムなのですか?
# もちろんWindowsは他のディレクトリにもファイルを配置していますが…。次にベースアドレスを指定することで改善するにもかかわらず指定しようとしないのはなぜでしょうか? ASLRを意識してとありますが、それならASLRの存在するVista以降の環境での読み込み時間を確認すべきです。
DLLの遅延読み込みを指定すると、DLL内の関数が呼び出された時点でDLLを読み込むようになります。そのため起動時の読み込み時間が削減できるかもしれないという期待です。また、滅多に呼ばれない関数ならDLLを読み込まずに済むこともあります。
-
私自身も4000という規模の実行可能ファイルを扱うシステムは見たことも聞いたことももちろん自分で携わったこともありませんが
- VC6->VC8でロード時間が遅くなった
- 今までベースアドレスは指定していない
- スタティックリンクなら問題が発生しない(改善されたをそう読み取りました)
ということから、私は MSVCR80.DLLなどのシステムファイルがWinSxSで配置されているからではないか?と推測します。
わかりませんけどね。もし、本当にこれが原因だとすると、回避策はありません。しいてあげれば、スタティックリンクするか、遅延ロードするかくらいです。
WinSxSについては、MSDNライブラリの Isolated Applications を参照してください。細かく書かれてます。
ただ、個人的にはこれらの対策の考慮よりも、4000という絶対値を減らす方法を検討したほうがいいのでは?と思います。
古いバージョンのものも動作するというのがどういう意味を指しているのかわかりませんが、新旧でファイルを共有しなければ問題にはなりませんよね?そういうわけにはいかないのでしょうか?
また、部分的に差し替える必要がある場合でも、互換性に齟齬が出ない範囲を丸ごと置き換えてしまえば、問題はないと思うのですが?もちろんバイナリレベルで互換性をとることも可能だと思います。実際うちの製品は8年?程度ですがバイナリ互換を維持し続けていますし。
実際に4000個すべてを1つのプロセスでロードするわけではないと思いますが、DLLを一つロードするためには、そのDLLのファイルサイズ分以上のメモリを必要とします。
ファイルの中には、コードのほかに、どこにコードがあるか?などのヘッダー情報や、リソース(実行可能ファイルにバージョンがついていないわけがないのですべてのモジュールに存在する)があります。これらのエリアは何に使うわけではないため利用できないメモリエリアとして確保されてしまいます。また、DLLの場合Cの外部初期化コードなどが埋め込まれるため、これも実質的には重複コードとして無駄な領域を増やす一助になります。
DLLの数は多くなればなるほど、これらの領域を増やすことになり、結果として利用可能メモリサイズが減るという状況を招きます。また、コードエリアが増えることで、それだけ利用するメモリが増え、スワップの発生確率を引き上げます。
数が増えると無視できない数字になってくると思うので、これらも考慮する必要があるものと思われます。
わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/