インストゥルメントクラスを取り、ロード時に-javaagent
をパラメーターとして受け取る多くのアプリも、コマンドラインに-noverify
を入力することを見てきました。
Java docは、-noverify
がクラス検証をオフにすることを述べています。
ただし、クラスをインストルメント化している場合でも、検証をオフにする必要があるのはなぜですか。
立ち上げ時間だと思います。クラスが正しいことを確認するには、クラスが読み込まれるときに時間がかかります。クラスは遅延してロードされる可能性があるため(アプリの起動時ではなく、初めて使用するとき)、これにより予期しない望ましくないランタイム遅延が発生する可能性があります。
実際、クラスは一般的にチェックする必要はありません。コンパイラーは、無効なバイトコードまたはクラス構成を出力しません。検証の理由は、クラスが1つのシステムで構築され、オンラインでホストされ、保護されていないインターネットを介して送信される可能性があるためです。このパスでは、悪意のある攻撃者がバイトコードを変更し、コンパイラが作成することのないものを作成する可能性があります。 JVMをクラッシュさせる可能性のあるもの、またはセキュリティ制限を回避できるもの。したがって、クラスは使用される前に検証されます。これがローカルアプリケーションの場合、通常はバイトコードを再度確認する必要はありません。
-javaagent
と組み合わせて使用すると、パフォーマンス上の理由からnotになる可能性が高くなりますが、エージェントが意図的に「無効な」バイトコードを作成するためです。
検証ルールの一部は非常に厳格であるため、無効なバイトコードが正常に実行される可能性があることに注意してください。たとえば、スーパーコンストラクターが呼び出される前に、コンストラクターでthis
にアクセスしないでください。これは、この時点では変数が初期化されていないためです。しかし、他にもやりたいことがあるかもしれません(JRebelの例を参照)。次に、-noverify
を使用してそのルールを回避します。
デバッグ中!実際、それが私が今やっていることであり、私がこの質問に出くわした方法です。 Terracottaでは、多くのバイトコードインストルメンテーションを行っています。クラスアダプターをデバッグするときに検証機能をオフにすると、実行時にどこでエラーが発生するかを正確に確認できる場合があります。
そうです、私たちは検証者が本番環境に留まることを望んでいます。
-noverify
なしでJRebelを使用すると、起動時に次の警告が表示されます。
JRebel: '-noverify'がありません。コンストラクターの変更/追加/削除は有効になりません!
そのため、-noverify
を使用すると、バイトコードの再インストルメンテーションで、他の方法では不可能ないくつかのことを実行できます。
以前は起動時間が少し問題でした。ただし、ベリファイアはプロセッサと同様に高速になりました。 JDK6 javacでコンパイルされたコードには、デフォルトで追加情報が含まれ、検証のステップが速くなります。 Apache Harmonyは、はるかに高速な検証アルゴリズムを使用します。
一部の非常に古いバージョンのjavacは、不正なバイトコードを生成しました。実際、Sun PlugInには、壊れたクラスファイルを検証するための修正コードがまだ含まれています。
Java 6で導入された新しいベリファイアは、コード操作の処理が非常に複雑です。
これを見てください: http://chrononsystems.com/blog/Java-7-design-flaw-leads-to-huge-backward-step-for-the-jvm
および関連するバグレポート: http://bugs.Sun.com/view_bug.do?bug_id=8009595