Delphiでアプリケーションを作成するときにアクセス違反を見つけて修正するために役立つヒントを教えてください。
アクセス違反は、通常、オブジェクトなど、まだ作成されていないメモリ内の何かにアクセスしようとしたことが原因であると思いますか?
何がアクセス違反を引き起こすのかを特定するのは難しく、それから、それらを試行/停止/修正するために必要な変更を行う場所を特定することは困難です。
例は、私が現在取り組んでいる個人的なプロジェクトです。 TTreeView Node.Dataプロパティに各ノードのデータを保存しています。ノードは複数選択してエクスポートできます(エクスポートは選択した各ノードを反復処理し、特定のデータをテキストファイルに保存します。テキストファイルに保存される情報は、nodes.dataに保存されます)。ファイルをツリービューにインポートすることもできます(テキストファイルの内容をnode.dataに保存します)。
この例の問題は、ファイルをツリービューにインポートしてからエクスポートすると、完璧に機能することです。ただし、実行時にノードを追加してエクスポートすると、次のようになります。
「モジュール 'Project1.exe'のアドレス00405772のアクセス違反。アドレス00000388の読み取り。」
それについての私の考えは、作成されたノードにデータを割り当てる方法である必要があり、インポートされたときに割り当てる方法とは異なる可能性がありますが、それはすべて大丈夫です。アクセス違反はエクスポート時にのみ表示され、インポートされたファイルでは決して発生しません。
上記の例の修正を探しているわけではありませんが、主にそのようなタイプのエラーを見つけて修正する方法についてのアドバイス/ヒントを探しています。アクセス違反は頻繁に発生しませんが、アクセス違反を追跡して修正するのは非常に困難です。
したがって、アドバイスやヒントは非常に役立ちます。
これは、コードが許可されていないメモリの一部にアクセスしていることを意味します。これは通常、間違ったメモリを指すポインターまたはオブジェクト参照があることを意味します。おそらく初期化されていないか、すでにリリースされているためです。
Delphiなどのデバッガーを使用します。 AVが発生したコードの行がわかります。そこから、コールスタックやローカル変数などを見て問題を特定します。デバッグDCUでコンパイルする場合にも役立つことがあります。
クライアント側でのみ発生するためデバッガがない場合は、MadExceptまたはJclDebugを使用してコールスタックで例外をログに記録し、送信することができます。詳細は少なくなりますが、正しい方向を示す場合があります。
より積極的にチェックすることで、この種の問題を早期に発見できるツールがいくつかあります。 FastMMメモリマネージャには、このようなオプションがあります。
編集
「モジュール 'Project1.exe'のアドレス00405772のアクセス違反。アドレス00000388の読み取り。」
そのため、モジュール 'Project1.exe'のアドレス00405772でAVが発生します。 Delphiデバッガーにより、適切なコード行が表示されます(またはエラー検索を使用します)。
アドレス00000388のメモリを読み取ろうとしています。これは00000000(nil)に非常に近いため、nilの配列または動的配列へのポインター/参照にアクセスすることを意味します。バイトの配列の場合、アイテム388になります。または、かなり大きなオブジェクトのフィールド、または多くのフィールドを持つレコードにすることもできます。オブジェクトまたはレコードのポインター/参照はnilになります。
デバッガーで実行しているときに、本当に見つけにくいアクセス違反が常に発生するとは限りません。さらに悪いことに、彼らは私ではなく顧客に起こります。受け入れられた答えはこれについて言及していますが、私はそれをより詳細に与える必要があると本当に思います:MadExceptは貴重なコンテキスト情報を提供し、コードが失敗する場所や未処理の例外がある場所を確認するのに役立つスタックトレースバックを提供します(アクセス違反のためだけではありません)。顧客がプログラム内から直接バグレポートをメールで送信する方法も提供します。これにより、ベータテスターまたはユーザーによって報告および修正されるアクセス違反が増加します。
第二に、コンパイラーのヒントと警告が実際にはいくつかの一般的な問題を検出していることに気づきました。ヒントと警告をクリーンアップすると、多くのアクセス違反やその他の微妙な問題が見つかる場合があります。たとえば、デストラクタを適切に宣言し忘れると、コンパイラの警告が発生する可能性がありますが、実行時には重大な問題が発生します。
第三に、PeganzaのPascal Analyzerなどのツールを見つけました。Delphiの一部のエディションの監査およびメトリック機能は、問題のあるコード領域を見つけるのに役立ちます。単一の具体例として、Pascalアナライザーは、クラッシュまたはアクセス違反につながる重要なことを忘れていた場所を見つけました。
第4に、別の開発者にコードを批判させる手法に勝るものはありません。少しひどい感じがするかもしれませんが、できれば何かを学び、自分のやっていることをうまくやることができます。可能性は、ツリービューを使用する方法よりも多くの方法があり、あなたがしている作業を行う方法よりも多く、より良いアーキテクチャであり、物事をきれいに行う方法は、より信頼性の高いコードをもたらすでしょう触れるたびに壊れません。ここでは、クリーンなコードを生成するためのルールの有限リストではなく、生涯にわたる努力と程度の問題です。無邪気なコードが、潜在的なクラッシュ、アクセス違反、競合状態、フリーズ、デッドロックの温床になる可能性があることに驚かれることでしょう。
以前の回答では言及されていなかった他のデバッグまたは「コードガード」技術に言及したいだけです。
「ローカル」ツール:
* DebugModeでFastMMを使用します-メモリの割り当てを解除するたびにゼロを書き込みます。これにより、プログラムは非常に遅くなりますが、解放されたオブジェクトにアクセスしようとするなどのエラーを見つける可能性が非常に高くなります。
* Obj.Freeの代わりに FreeAndNil (Obj)を使用します。一部の人々は、それが問題を引き起こすと不平を言っていましたが、実際にこれが起こるかもしれない明確な例を提供していませんでした。さらに、Emarcaderoは最近、マニュアルでFreeAndNilを使用することを推奨しました(最終的に!)。
*アプリケーションは常にリリースモードとデバッグモードでコンパイルします。プロジェクトオプションがデバッグモードに正しく設定されていることを確認します。デバッグモードのデフォルト設定は正しくない/完全ではありません-最後にDelphi XE7と東京ではありません。いつか彼らはデバッグモードの正しいオプションを設定するでしょう。したがって、有効にする like :
サードパーティツール: