印刷ビューの終了

Java SE 7 デスクトップテクノロジのトラブルシューティングガイド

印刷ビュー

ドキュメント情報

はじめに

1. はじめに

2. AWT

3. Java 2D

3.1 レンダリングパイプラインおよびそのプロパティーの変更

3.1.1 Solaris OS および Linux:デフォルト X11 パイプラインの使用

3.1.1.1 X11 ピックスマップの使用に関係するプロパティー

X11 パイプラインでのピックスマップの使用の無効化

X11 パイプラインでの共有メモリーピックスマップの使用の無効化/強制

3.1.1.2 X11 パイプラインでの MIT 共有メモリー拡張の使用

X サーバーや Java 2D で使用可能な共有メモリーの増加

X11 パイプラインでの共有メモリー拡張の使用の無効化

3.1.1.3 SPARC 上の Solaris OS:特定の構成での DGA の使用

画面へのレンダリングでの DGA 拡張の使用の検出

DGA の使用に起因する典型的な問題

Java 2D での DGA の使用の制御

3.1.2 SPARC 上の Solaris OS:Java 2D で使用されるデフォルトビジュアルの変更

3.1.3 Windows OS:デフォルトの DirectDraw/GDI パイプラインの使用

3.1.3.1 DirectDraw の使用の無効化

3.1.3.2 DirectDraw パイプラインの使用の強制

3.1.3.3 組み込みパントメカニズムの無効化

3.1.3.4 DirectDraw Blit 操作の無効化

3.1.4 Windows OS:Direct3D パイプラインの使用 (フルスクリーンモード)

3.1.4.1 Direct3D パイプラインの無効化

3.1.4.2 Direct3D パイプラインの使用の強制

3.1.4.3 Direct3D パイプラインのレンダリングの問題の診断

3.1.5 OpenGL パイプラインの使用 (SolarisOS、Linux、および Windows)

3.1.5.1 OpenGL パイプラインの有効化

3.1.5.2 最小要件

3.1.5.3 最新の OpenGL ドライバ

3.1.5.4 起動の問題の診断

3.1.5.5 レンダリングおよびパフォーマンスの問題の診断

3.2 一般的なパフォーマンス問題

3.2.1 ハードウェア高速化レンダリングプリミティブ

3.2.2 Java 2D プリミティブトレースを使用した非高速化レンダリングの検出と回避

3.2.3 低いレンダリングパフォーマンスの原因

3.2.3.1 高速化レンダリングと非高速化レンダリングの混在

3.2.3.2 最適でないレンダリングプリミティブの使用

3.2.3.3 ヒープベースのデスティネーション表面 (BufferedImage) の使用

3.2.3.4 組み込み高速化メカニズムの無効化

getDataBuffer() によるピクセルへの直接アクセス

各コピーに先立つスプライトへのレンダリング

高速化メモリーリソースの枯渇

3.2.4 ソフトウェアのみのレンダリングのパフォーマンス改善

3.2.4.1 最適化されたサポートのあるイメージ型やイメージ操作の使用

3.2.4.2 透明と半透明

3.3 テキスト関係の問題

3.3.1 テキストレンダリング中のアプリケーションクラッシュ

3.3.2 テキストの外観の違い

3.3.3 メトリックス

3.4 Java 2D 印刷

4. Swing

5. 国際化

6. Java Sound

7. アプレットと Java Web Start アプリケーション

8. バグレポートの送信

A. Java 2D のプロパティー

B. 致命的エラーログ

第 3 章

Java 2D

この章では、Java 2D API で発生する可能性のあるもっとも一般的な問題のいくつかをトラブルシューティングするための情報と指針を提供します (次の各セクションを参照)。

Java 2D プロパティーのサマリーについては、「付録 A: Java 2D のプロパティー」を参照してください。

Java 2D FAQ も参照してください。

3.1 レンダリングパイプラインおよびそのプロパティーの変更

Java 2D では一連のパイプラインが使用されますが、これは大まかに、プリミティブをレンダリングするためのさまざまな方法として定義できます。これらのパイプラインは次のとおりです。

別のパイプラインを選択したりパイプラインのプロパティーを操作したりすれば、問題の原因を特定できたり、しばしば回避方法を発見できたりする可能性があります。

Java 2D の問題のトラブルシューティングに役立つ可能性のある手順を次に示します。

  1. 構成で使用されているデフォルトパイプラインを確認します。

  2. パイプラインを別のものに変更するか、デフォルトパイプラインのプロパティーを変更します。

  3. 問題が解消すれば、回避方法が見つかったことになります。

  4. 問題が継続する場合は、別のプロパティーを変更するか別のパイプラインに変更してみます。

このセクションでは、Java 2D のパイプラインやそのプロパティーを変更する方法を、次のオペレーティングシステムごとに説明します。UNIX (Solaris OS と Linux) および Windows。

Solaris OS および Linux 上のデフォルト X11 パイプラインについては、次の情報を提供します。

Windows 上のデフォルト DirectDraw/GDI パイプラインについては、次の情報を提供します。

Windows 上の代替 Direct3D パイプラインについては、次の情報を提供します。

またこのセクションでは、Solaris OS、Linux、および Windows 上で OpenGL パイプラインを代替パイプラインとして使用する情報も提供します。

3.1.1 Solaris OS および Linux:デフォルト X11 パイプラインの使用

UNIX プラットフォームのデフォルトパイプラインは X11 パイプラインです。このパイプラインでは、画面へのレンダリングや、特定タイプのオフスクリーンイメージ (VolatileImage など) または「互換性のある」イメージ (GraphicsConfiguration.createCompatibleImage() メソッドで作成されたイメージ) へのレンダリングを行う際に、X プロトコルが使用されます。そのようなタイプのイメージは、X11 ピックスマップ内に格納すればパフォーマンスを改善できます (特にリモート X サーバーの場合)。

さらに、Java 2D では特定の場合に、X サーバー拡張 (MIT X 共有メモリー拡張、ダイレクトグラフィックスアクセス拡張、BufferStrategy API 使用時のダブルバッファリング用ダブルバッファー拡張など) が使用されます。

構成によっては、追加パイプラインの OpenGL パイプラインによってパフォーマンスが向上することもあります。

3.1.1.1 X11 ピックスマップの使用に関係するプロパティー

Java 2D ではデフォルトで、特定タイプのオフスクリーンイメージの格納やキャッシングに X11 ピックスマップが使用されます。ピックスマップに格納できるイメージのタイプは、次のものだけです。

イメージの格納にピックスマップを使用するメリットは、ドライバの判断でフレームバッファーのビデオメモリー内に配置できる点にあります (そうした場合、これらのピックスマップを画面や別のピックスマップにコピーする際の速度が改善される)。

ピックスマップを使用すれば、通常はパフォーマンスが向上します。ただし、場合によっては逆になることもあります。そのような場合は通常、X プロトコルを使って実行できない操作 (アンチエイリアス、アルファ合成、単純な移動変換よりも複雑な変換など) が使用されています。

これらの操作については、X11 パイプラインは組み込みソフトウェアレンダラを使ってレンダリングを行う必要があります。これにはほとんどの場合、ピックスマップの内容を読み取って (リモート X サーバーの場合はネットワーク経由で) システムメモリーに格納し、レンダリングを実行したあと、それらのピクセルを元のピックスマップに送信するという操作が含まれます。そのような操作ではパフォーマンスが大幅に低下する可能性があります (特に X サーバーがリモートの場合)。

X11 パイプラインでのピックスマップの使用の無効化

Java2D でのピックスマップの使用を無効にするには、Java VM に次のプロパティーを渡します。-Dsun.java2d.pmoffscreen=false

X11 パイプラインでの共有メモリーピックスマップの使用の無効化/強制

ピックスマップからのピクセルの読み取りを必要とするそのような操作の、全体のパフォーマンスに対する影響を最小限に抑えるため、X11 パイプラインは読み取り頻度の高いイメージの格納に共有メモリーピックスマップを使用します。共有メモリーピックスマップを使用できるのは、ローカル X サーバーの場合だけです。

共有メモリーピックスマップを使用するメリットは、X11 プロトコルをバイパスしてパイプライン内のピクセルにパイプラインから直接アクセスできる点にあり、その結果、パフォーマンスが向上します。

イメージはデフォルトでは通常の X サーバーピックスマップ内に格納されますが、あとでそのようなイメージからの過剰な読み取りがパイプラインによって検出された場合には、共有メモリーピックスマップにイメージを移動できます。イメージのコピー回数が十分な数に達したら、元のサーバーピックスマップにイメージを移動できます。

このパイプラインでは、共有メモリーピックスマップの使用を制御する方法が 2 つ用意されています。それらを無効にする方法と、すべてのイメージが常に共有メモリーピックスマップに強制的に格納されるようにする方法です。

まず共有メモリーピックスマップの強制を試してください。多くの場合でパフォーマンスが改善されます。ただし、特定のビデオボード/ドライバ構成では、レンダリングアーティファクトやクラッシュを回避するために、共有メモリーピックスマップの無効化が必要となることがあります。

3.1.1.2 X11 パイプラインでの MIT 共有メモリー拡張の使用

Java 2D の X11 パイプラインではデフォルトで、MIT 共有メモリー拡張 (MIT SHM) が使用されます。この拡張を使えば、クライアント (Java アプリケーション) と X サーバー間のデータ交換の速度が向上するため、Java アプリケーションのパフォーマンスが大幅に改善される可能性があります。

X サーバーや Java 2D で使用可能な共有メモリーの増加

Solaris OS リリース 8 以前ではときどき、システム (および特に X サーバー) で使用可能な共有メモリーの量を増やす必要がありましたが、これは、デフォルトが低すぎてレンダリングのパフォーマンスが低下することがあったからです。共有メモリーや共有メモリーセグメントの量を増やすと、パフォーマンスが向上する可能性があります。

Solaris OS でデフォルト設定を変更するには、/etc/system ファイルを編集し、shmsys:shminfo_* 設定を次の例のように変更します。これは、Solaris 9 OS 以降では不要です。

set shmsys:shminfo_shmmax=10000000
set shmsys:shminfo_shmni=200
set shmsys:shminfo_shminfo=150

Linux でこの設定を構成するには、/proc/sys/kernel/shm* ファイルを編集します。

X11 パイプラインでの共有メモリー拡張の使用の無効化

古い X サーバーや共有メモリー拡張で問題 (クラッシュやレンダリングアーティファクトなど) が発生する場合、拡張を無効にできると便利です。MIT SHM の使用を無効にするには、J2D_USE_MITSHM 環境変数を false に設定します。

3.1.1.3 SPARC 上の Solaris OS:特定の構成での DGA の使用

SPARC ハードウェアでは、フレームバッファーが Sun の DGA (ダイレクトグラフィックスアクセス) X サーバー拡張をサポートしていて、フレームバッファーにアクセスするための対応するモジュールが Java 2D に含まれている場合、画面へのレンダリングに DGA が使用されます。

オフスクリーンイメージはすべて Java ヒープメモリー内に存在しており、それらへのレンダリングには Java 2D のソフトウェア専用レンダリングパイプラインが使用されます。これは、オフスクリーンイメージに X11 ピックスマップが使用される通常の UNIX 構成とは異なっています。

画面へのレンダリングでの DGA 拡張の使用の検出

画面へのレンダリング時に DGA 拡張が使用されているかどうかを検出するには、何らかのレンダリングを行うか GUI を表示する任意の Java アプリケーションを実行し、そのアプリケーション起動時に /tmp/wg* ファイルが作成されたかチェックします。アプリケーションを終了し、ファイルが削除されたことを確認します。その場合、このシステムでは Java 2D が DGA を使用しています。

DGA の使用に起因する典型的な問題

DGA ではフレームバッファーのビデオメモリーに直接アクセスできるため、典型的な問題として、ウィンドウ境界の外側の破損、完全なシステム、X サーバーロックアップなどが挙げられます。

Java 2D での DGA の使用の制御

DGA が使用されていることが確認できた場合、最初に試すべきことは、その無効化です。これを行うには、NO_J2D_DGA 環境変数を true に設定します。するとデフォルトの UNIX パスで強制的に、画面へのレンダリングに X11 のみが使用され、オフスクリーンイメージの高速化にピックスマップが使用されるようになります。

場合によっては、ピックスマップの使用を有効にしつつ、DGA も画面へのレンダリングに使用したほうが有利なことがあります。オフスクリーンイメージの高速化にピックスマップの使用を強制するには、アプリケーションの起動時に次のプロパティーを設定します。-Dsun.java2d.pmoffscreen=true

3.1.2 SPARC 上の Solaris OS:Java 2D で使用されるデフォルトビジュアルの変更

SPARC プラットフォームの特定のビデオボードでは、複数のビジュアルが X サーバーから使用できます。Java 2D はデフォルトで最適なビジュアルを選択しようとしますが、この「最適」というのは通常、ビットの深さがより深いビジュアルを指します。たとえば一部の Solaris OS リリースでは、デフォルト X11 ビジュアルは 8 ビット疑似カラーですが、24 ビットのビジュアルも使用できます。そのような場合、Java 2D は、Java ウィンドウのデフォルトとして 24 ビットトゥルーカラービジュアルを選択します。

別のビジュアルに対応する GraphicsConfiguration オブジェクトで Java トップレベルウィンドウを作成することも可能ですが、場合によっては、代わりに別のデフォルトビジュアルを Java に使用させる必要が生じることがあります。これを行うには、FORCEDEFVIS 環境変数を設定します。これは、true に設定してデフォルト X サーバービジュアルの使用を (たとえ最適でなくても) 強制することができる一方で、xdpyinfo などのツールで報告されたビジュアル ID に対応する 16 進数に設定することもできます。

X サーバーのデフォルトビジュアルを確認するには、xdpyinfo コマンドを実行し、default visual id のフィールドを確認します。

3.1.3 Windows OS:デフォルトの DirectDraw/GDI パイプラインの使用

Windows プラットフォームのデフォルトパイプラインは、DirectDraw パイプラインと GDI パイプラインを組み合わせたものであり、DirectDraw パイプラインで実行される操作もあれば、GDI パイプラインで実行される操作もあります。高速化されたオフスクリーンやオンスクリーン表面へのレンダリングには、DirectDraw と GDI の API が使用されます。

Java SE 6 リリース以降では、ドライバが要件を満たしていれば、アプリケーションがフルスクリーンモードに入るときに新しい Direct3D パイプラインを使用できます。Direct3D パイプラインで発生する可能性のある問題として、レンダリングアーティファクト、クラッシュ、パフォーマンス関係の問題などが挙げられます。

構成によっては、追加パイプラインの OpenGL パイプラインによってパフォーマンスが向上することもあります。

3.1.3.1 DirectDraw の使用の無効化

DirectDraw が無効になると、GDI ですべての操作が実行されます。DirectDraw の使用を無効にするには、次のフラグを指定します。-Dsun.java2d.noddraw=true。この場合、オフスクリーンイメージはすべて Java ヒープ内に作成され、それらへのレンダリングはデフォルトソフトウェアパイプラインで行われます。オンスクリーンレンダリングや画面へのオフスクリーンイメージのコピーはすべて、GDI を使って実行されます。

3.1.3.2 DirectDraw パイプラインの使用の強制

何らかの理由でパイプラインがデフォルトで無効化された場合にそれを有効にするには、-Dsun.java2d.noddraw=false フラグを VM に指定します。

ただし通常は、そもそも無効にされた理由が存在するので、強制しないほうが得策です。

3.1.3.3 組み込みパントメカニズムの無効化

一般に、DirectDraw パイプラインはオフスクリーン表面をフレームバッファーのビデオメモリー内に配置しようとしますが、これにより、それらの表面を画面やほかの高速化された表面にコピーする操作が高速化されるほか、特定のグラフィックス操作のハードウェア高速化レンダリングが可能となります。

ただし、パイプラインが DirectDraw API を使って実行できない操作 (アルファ合成、変換、アンチエイリアスなどを使用する操作) については、ソフトウェアパイプラインを使ってレンダリングが実行されます。これは場合によっては、VRAM 内に存在するデスティネーション表面のピクセルを読み取ってシステムメモリーに格納する必要があることを意味しますが、それは非常にコストの高い操作です。

VRAM ベースの表面への非高速化レンダリングの影響を限定するために、パントメカニズムが存在します。このメカニズムは、読み取り頻度が高いことが検出された表面をシステムメモリーに移動します。表面のコピー回数が十分な数に達したと判断されると、表面が元のビデオメモリーに昇格される可能性があります。

特定のビデオボード/ドライバの組み合わせでは、システムメモリーベースの DirectDraw 表面がレンダリングアーティファクトやその他の問題の原因となることが知られています。DirectDraw パイプラインには、システムメモリー表面が使用されないようにパントメカニズムを無効にするための方法が用意されています。

組み込み表面パントメカニズムを無効にするには、次のフラグを Java VM に指定します。-Dsun.java2d.ddforcevram=true。この場合、ソフトウェアループが操作ごとに VRAM からピクセルを読み取る可能性があるため、パフォーマンスが低下する可能性があります。その場合は、DirectDraw パイプラインの無効化 (上を参照) を検討できます。

3.1.3.4 DirectDraw Blit 操作の無効化

Blit 操作 (Bit Block Transfer) では 2 つのビットマップパターンが合成されます。この操作は基本的に、Graphics.drawImage() API の呼び出しに対応します。

場合によっては、DirectDraw Blit 操作を無効にすることでレンダリングの問題を回避できます。代わりに GDI Blit が使用されます。この場合、パフォーマンスが低下する可能性があります。代わりに DirectDraw パイプラインの無効化を検討してください。

DirectDraw Blit 操作の使用を無効にするには、パラメータ -Dsun.java2d.ddblit=false を Java VM に渡します。

3.1.4 Windows OS:Direct3D パイプラインの使用 (フルスクリーンモード)

Java SE 6 リリース以降の Direct3D パイプラインでは、レンダリングに Direct3D API が使用されます。フルスクリーンモードではこのパイプラインがデフォルトで有効にされます (ドライバが、必要な機能とそのレンダリング品質レベルをサポートしている場合)。

Java SE 5 とそれよりあとのリリースの両方で、Direct3D パイプラインを有効にしたりその使用を強制したりできます (下のサブセクションを参照)。

アルファ合成、アンチエイリアス、変換などのレンダリング操作を大量に使用するアプリケーションでは、Direct3D パイプラインを有効にすることを検討してください。

ただし、このパイプラインをアプリケーションで有効にすることを決定する際には注意してください。たとえば、一部の組み込みビデオチップセット (大部分のノートブックで使用されているもの) は、たとえ Java 2D パイプラインの品質要件を満たしていても、Direct3D 使用時には良好なパフォーマンスを示しません。

3.1.4.1 Direct3D パイプラインの無効化

一部の古いビデオボード/ドライバの組み合わせでは、Direct3D パイプラインで問題 (レンダリングとパフォーマンスの両方) が発生することが知られています。そのような場合に Java SE 5 以降のリリースでパイプラインを無効にするには、パラメータ -Dsun.java2d.d3d=false を Java VM に渡すか、J2D_D3D 環境変数を false に設定します。

3.1.4.2 Direct3D パイプラインの使用の強制

Java SE 5 以降のリリースで、ウィンドウモードとフルスクリーンモードの両方で Direct3D パイプラインを有効にするには、パラメータ -Dsun.java2d.d3d=true を使用するか、J2D_D3D 環境変数を true に設定します。パイプラインが有効にされるのは、ドライバが最小限必要な機能をサポートしている場合だけです。

3.1.4.3 Direct3D パイプラインのレンダリングの問題の診断

Java SE 6 リリースでは、さまざまな Direct3D ラスタライザを強制することで、いくつかのレンダリングの問題 (欠落したピクセルや異常なレンダリングなど) を診断できます。J2D_D3D_RASTERIZER 環境変数を次のいずれかに設定します。refrgbhaltnl

これらのラスタライザの説明については、Direct3D のドキュメントを参照してください。デフォルトでは、通知された機能に基づいて最適なラスタライザが選択されます。具体的には、ref ラスタライザでは、Microsoft 製のリファレンス Direct3D ラスタライザの使用が強制されます。このラスタライザでレンダリングの問題が再現できない場合、その問題はほぼ間違いなくビデオドライバのバグです。

rgb ラスタライザが使用可能なのは、Direct3D SDK がインストールされている場合だけです。この SDK は Microsoft Game Technologies Center から取得できます。

Direct3D パイプラインのテキストレンダリングでパフォーマンスや品質の問題が発生する場合、Direct3D パイプラインのグリフキャッシュで、デフォルトのアルファテクスチャーの代わりに ARGB テクスチャーを使用することを強制できます。これを行うには、J2D_D3D_NOALPHATEXTURE 環境変数を true に設定します。

3.1.5 OpenGL パイプラインの使用 (SolarisOS、Linux、および Windows)

OpenGL パイプラインは、J2SE 5.0 リリースではじめて Solaris OS、Linux、および Windows 上で使用可能になりました。この代替パイプラインでは、VolatileImageBufferStrategy API で作成されたバックバッファー、および画面へのレンダリング時に、ハードウェア高速化されたクロスプラットフォームの OpenGL API が使用されます。

このパイプラインはデフォルト (X11 または GDI/DirectDraw) のパイプラインに比べ、特定のアプリケーションでパフォーマンス上の大きな利点を提供できます。アルファ合成、アンチエイリアス、変換などのレンダリング操作を大量に使用するアプリケーションでは、このパイプラインを有効にすることを検討してください。

OpenGL パイプラインで高速化される Java 2D 操作の完全な一覧については、記事「Behind the Graphics2D: The OpenGL-based Pipeline」を参照してください。

3.1.5.1 OpenGL パイプラインの有効化

現時点では、OpenGL パイプラインはデフォルトで無効になっています。OpenGL パイプラインの有効化を試みるには、次のオプションを JVM に指定します。

-Dsun.java2d.opengl=true

OpenGL パイプラインが特定のスクリーンに対して正常に初期化されたかどうかに関する、冗長なコンソール出力を受け取るには、オプションを True に設定します (大文字「T」に注意)。

-Dsun.java2d.opengl=True

3.1.5.2 最小要件

ハードウェアまたはドライバが最小要件を満たしていなければ、OpenGL パイプラインは有効にされません。何らかの理由で次の要件のいずれかが満たされない場合、Java 2D はフォールバックしてデフォルトパイプライン (Solaris/Linux では X11、Windows では GDI/DirectDraw) を使用するため、アプリケーションは正しく動作し続けますが、OpenGL の高速化は失われます。

Solaris OS および Linux の最小要件は、次のとおりです。

Windows OS の最小要件は、次のとおりです。

3.1.5.3 最新の OpenGL ドライバ

OpenGL パイプラインは OpenGL API およびベースとなるグラフィックスハードウェアやドライバに強く依存しているため、最新のグラフィックスドライバがマシンにインストールされているのを確認することが非常に重要です。ドライバは、グラフィックスカードの製造元の Web サイトからダウンロードできます (次の表を参照)。

製造元
Web サイト
プラットフォーム
動作確認済みのカード
ATI
Linux、Windows
Radeon 8500 以上、FireGL シリーズ
Nvidia
x64 上の Solaris OS、Linux、Windows
GeForce 2 シリーズ以上、Quadro FX シリーズ以上
Sun
SPARC 上の Solaris OS
Expert3D シリーズ、XVR-500、XVR-600、XVR-1200、XVR-2500
Xi Graphics
x86 上の Solaris OS、Linux
各種 (Xi Graphics で確認)
3.1.5.4 起動の問題の診断

前述したように、特定のマシン上でさまざまな理由で OpenGL パイプラインが有効にされない場合があります。たとえば、ドライバが正しくインストールされていない可能性や、報告されたバージョン番号が不十分である可能性があります。あるいは、マシンに搭載されている古いグラフィックスカードが OpenGL の適切なバージョンや拡張をサポートしていない可能性もあります。

Java SE 6 以降のリリースで、OpenGL ベースの Java 2D パイプラインの起動手順に関する詳細情報を取得するには、次のように J2D_TRACE_LEVEL 環境変数を使用します。

Windows の場合:

# set J2D_TRACE_LEVEL=4
# java -Dsun.java2d.opengl=True YourApp

Solaris OS および Linux の場合:

# export J2D_TRACE_LEVEL=4
# java -Dsun.java2d.opengl=True YourApp

その出力は、プラットフォームや取り付けられたグラフィックスハードウェアに応じて異なりますが、OpenGL パイプラインがユーザーの構成で正常に有効にされない理由に関する何らかの洞察を提供してくれます。この出力は特に、Sun の Java 2D チーム宛のバグレポートを提出する際に役立ちます (バグレポートについては後述)。

3.1.5.5 レンダリングおよびパフォーマンスの問題の診断

OpenGL パイプラインはベースとなるグラフィックスハードウェアやドライバに非常に強く依存しているため、レンダリングやパフォーマンスの問題の原因が Java 2D、OpenGL ドライバのどちらなのかを判定しかねる場合があります。

Java SE 6 リリースでの OpenGL パイプラインの新機能の 1 つは、VolatileImage 使用時のレンダリングパフォーマンスの改善と VRAM 消費量の低減を図る GL_EXT_framebuffer_object 拡張の使用です。この「FBO」コードパスは、OpenGL パイプラインが有効なときにデフォルトで有効にされますが、それは、グラフィックスハードウェアとドライバがこの OpenGL 拡張をサポートしている場合だけです。この拡張は一般に、Nvidia GeForce/Quadro FX シリーズ以降および ATI Radeon 9500 以降で使用できます。「FBO」コードパスがアプリケーションの問題の原因となっている疑いがある場合、次のシステムプロパティーを設定してそれを無効にすることができます。

-Dsun.java2d.opengl.fbobject=false

このプロパティーが設定されると、Java 2D は古い「pbuffer ベースの」コードパスにフォールバックします。

特定の Java 2D 操作で得られる視覚的な結果が、OpenGL パイプラインを有効にしたときとしなかったときで異なる場合、それはおそらく、グラフィックスドライバのバグを示しています。同様に、OpenGL パイプラインを有効にしたときに、しなかった場合よりも Java 2D レンダリングのパフォーマンスが大幅に悪化する場合、その原因はおそらくドライバまたはハードウェアの問題です。

いずれにしても、通常のバグ報告チャネルを通じて詳細なバグレポートを提出してください (第 8 章「バグレポートの提出」を参照)。バグレポートの提出時にはできるだけ詳しく記述し、必ず次の情報を含めてください。

3.2 一般的なパフォーマンス問題

このセクションには次のサブセクションが含まれます。

3.2.1 ハードウェア高速化レンダリングプリミティブ

パフォーマンス問題の原因についての理解を深めるため、ハードウェア高速化の意味について考えてます。

一般に、ハードウェア高速化レンダリングは 2 つのカテゴリに分けられます。

理想的には、高速化対象表面に対して実行される操作はすべて、ハードウェアで高速化されます。この場合、アプリケーションはプラットフォームによって提供されるメリットを最大限に享受できます。

残念ながら多くの場合、デフォルトパイプラインはレンダリングにハードウェアを使用できません。その原因は、パイプラインの制限やベースとなるネイティブ API にあります。たとえば、ほとんどの X サーバーは、アンチエイリアスプリミティブのレンダリングやアルファ合成をサポートしません。

パフォーマンス問題の原因の 1 つは、実行される操作がハードウェア高速化されない場合にあります。デスティネーション表面が高速化される場合でも、その一部のプリミティブが高速化されない可能性があります。

ハードウェア高速化が使用されていない場合を検出する方法を知ることが重要です。それを知れば、パフォーマンスの改善が容易になる可能性があります。

3.2.2 Java 2D プリミティブトレースを使用した非高速化レンダリングの検出と回避

高速化されないレンダリングを検出するには、Java 2D プリミティブトレースを使用できます。

Java 2D には組み込みのプリミティブトレースが含まれています。「Java 2D テクノロジのシステムプロパティー」の trace プロパティーの説明を参照してください。

アプリケーションの実行時に -Dsun.java2d.trace=count を指定します。アプリケーションが終了すると、プリミティブのリストとそれらのカウントがコンソールに出力されます。

MaskBlit プリミティブや任意の General* プリミティブが表示された場合、それは通常、レンダリングの一部がソフトウェアループによって処理されていることを意味します。Linux 上で、半透明の BufferedImage に対して drawImage を実行して VolatileImage に書き込む場合の出力を、次に示します。

sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, "Integer BGR Pixmap")sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntBgr)

デフォルトパイプラインの一般的な非高速化プリミティブのいくつかと、それらのトレース出力でのシグニチャーを次に示します。このトレースの大部分は Linux 上で取得したものです。プラットフォームや構成によっては何らかの違いが生じる可能性があります。

アプリケーションをトレース付きで実行し、不要な非高速化プリミティブを使用していないことを確認してください。

3.2.3 低いレンダリングパフォーマンスの原因

次の各サブセクションでは、低いレンダリングパフォーマンスの原因となる可能性のあるものをいくつか説明します。

3.2.3.1 高速化レンダリングと非高速化レンダリングの混在

特定のパイプラインでの高速化表面へのレンダリング時に、アプリケーションによってレンダリングされるプリミティブの一部しか高速化できない状況では、スラッシングが発生する可能性があります。パイプラインで常にレンダリングパフォーマンスの改善に向けた調整が試行されても、成功する可能性がおそらくほとんどないからです。

レンダリングプリミティブの大部分が高速化されないことが事前にわかっている場合、BufferedImage にレンダリングしてからバックバッファーや画面にコピーするか、あるいは前述のフラグのいずれかを使って非ハードウェア高速化パイプラインに切り替えたほうが得策です。

ただしこのアプローチを採用した場合、Java 2D でのハードウェア高速化の使用状況が将来改善されても、そのメリットをアプリケーションで享受できなくなる可能性があります。

たとえば、リモート X サーバーケースでの使用頻度の高いアプリケーション内でアンチエイリアスやアルファ合成などが多用されると、パフォーマンスが極度に低下する可能性があります。これを避けるには、-Dsun.java2d.pmoffscreen=false プロパティーを Java ランタイムに渡すかプログラム内で System.setProperty() API を使って設定して、ピックスマップの使用を無効にします。このプロパティーは一度しか読み取られないため、すべての GUI 関連操作の前に設定する必要があります。

3.2.3.2 最適でないレンダリングプリミティブの使用

目的の視覚効果を実現する際に、可能なかぎりもっとも単純なプリミティブを使用することをお勧めします。

たとえば、Graphics.drawLine() を使用して new Line2D().draw() は使用しません。結果は同じようにみえます。ただし、2 番目の操作では、通常レンダリングコストの非常に高い汎用形状としてレンダリングされるため、計算量が格段に多くなります。形状は、プリミティブトレース内で、アンチエイリアス設定や特定のパイプラインに応じてさまざまな方法で表示されますが、おそらく多数の *FillSpans または DrawPath プリミティブとして表示されます。

複雑な属性のもう 1 つの例は、GradientPaint です。これは、デフォルト以外の一部のパイプライン (OpenGL など) ではハードウェア高速化される可能性がありますが、デフォルトパイプラインではハードウェア高速化されません。したがって、パフォーマンスの問題が発生する場合に GradientPaint の使用を制限できます。

3.2.3.3 ヒープベースのデスティネーション表面 (BufferedImage) の使用

BufferedImage へのレンダリングでは、ほとんど常にソフトウェアループが使用されます。

例外として、一部の SPARC システムで、特定のイメージング操作を高速化するために VIS 命令セットが使用される場合があります。VIS 命令セットの Web サイトを参照してください。

レンダリングが高速化される機会を残すには、BufferStrategy または VolatileImage オブジェクトをレンダリング先として選択してください。

3.2.3.4 組み込み高速化メカニズムの無効化

Java 2D は特定タイプのイメージを高速化しようとします。VolatileImage などの高速化デスティネーションへのコピーを高速化するため、イメージの内容がビデオメモリーにキャッシュされる可能性があります。これらのメカニズムが知らないうちに (たとえば次のような場合に)、アプリケーションによって無効にされてしまう可能性があります。

getDataBuffer() によるピクセルへの直接アクセス

アプリケーションが getRaster().getDataBuffer() API を使って BufferedImage ピクセルにアクセスした場合、Java 2D は、キャッシュ内のデータが最新であることを保証できないため、そのようなイメージの高速化の試みをすべて無効にします。

この問題を避ける方法は 2 つあります。

各コピーに先立つスプライトへのレンダリング

アプリケーションがイメージを高速化表面 (VolatileImageBufferStrategy) にコピーする前にイメージに毎回レンダリングする場合、そのイメージは、高速化メモリーにキャッシュされるメリットを享受できません。その理由は、元のイメージが更新されるたびにキャッシュコピーを更新する必要があり、そのためにデフォルトのシステムメモリーベースの表面だけが使用されて、高速化されないからです。

高速化メモリーリソースの枯渇

アプリケーションが多数のイメージを使用すると、使用可能な高速化メモリーが使い果たされる可能性があります。これが本当にアプリケーションのパフォーマンス問題の原因となっている場合、リソースを管理しなければいけない可能性があります。

次の API を使えば、使用可能な高速化メモリーの量を要求できます。GraphicsDevice.getAvailableAcceleratedMemory()

さらに次の API を使えば、イメージが高速化されているかどうかを判定できます。Image.getCapabilities()

アプリケーションがリソースを使い果たしていることが判明した場合、次の方法で問題を処理できます。

3.2.4 ソフトウェアのみのレンダリングのパフォーマンス改善

アプリケーションが (BufferedImage へのレンダリングのみを行うかデフォルトパイプラインを非高速化パイプラインに変更したために) ソフトウェアのみのレンダリングに依存している場合、あるいはアプリケーションが混在されたレンダリングを行う場合でも、特定のパフォーマンス改善アプローチが存在します。

3.2.4.1 最適化されたサポートのあるイメージ型やイメージ操作の使用

プラットフォーム全体のサイズ制約のために、あるイメージ形式を別の形式に変換するための最適化されたルーチンは、Java 2D には限られた数しか含まれていません。最適化された直接ループが見つからない状況では、Java 2D は中間イメージ形式 (IntArgb) を介して変換します。この場合、パフォーマンスが低下します。

Java 2D プリミティブトレースを使用すればそのような状況を検出できます。

drawImage 呼び出しに対して 2 つのプリミティブが存在します。1 つ目はイメージをソース形式から中間 IntArgb 形式に変換し、2 つ目は中間 IntArgb から変換先の形式に変換します。

そのような状況を回避する 2 つの方法を次に示します。

3.2.4.2 透明と半透明

できれば、完全な半透明 (INT_ARGB など) のイメージではなく、1 ビット透明 (BITMASK) のイメージをスプライトとして使用することを検討してください。

完全なアルファを持つイメージの処理では、CPU の負荷がより高くなります。

1 ビット透明イメージを取得するには、GraphicsConfiguration.createCompatibleImage(w,h, Transparency.BITMASK) の呼び出しを使用します。

3.3 テキスト関係の問題

このセクションでは、テキストレンダリングに関係する可能性のあるいくつかの問題について説明します (次の各サブセクションを参照)。

3.3.1 テキストレンダリング中のアプリケーションクラッシュ

テキストレンダリング中にアプリケーションがクラッシュする場合は、まず致命的エラーログファイルをチェックしてください。このエラーログファイルの詳細については、「付録 B: 致命的エラーログ」を参照してください。fontmanager.dll 内でクラッシュが発生した場合やスタック内に fontmanager が存在している場合は、フォント処理コード内でクラッシュが発生したことになります。典型的なネイティブスタックフレームの例 (完全なログファイルからの抜粋) を次に示します。

Stack: [0x008a0000,0x008f0000),  sp=0x008ef52c,  free space=317k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [ntdll.dll+0x1888f]
C  [ntdll.dll+0x18238]
C  [ntdll.dll+0x11c76]
C  [MSVCR71.dll+0x16b3]
C  [MSVCR71.dll+0x16db]
C  [fontmanager.dll+0x21f9a]
C  [fontmanager.dll+0x22876]
C  [fontmanager.dll+0x1de40]
C  [fontmanager.dll+0x1da94]
C  [fontmanager.dll+0x48abb]
j  sun.font.FileFont.getGlyphImage(JI)J+0
j  sun.font.FileFontStrike.getGlyphImagePtrs([I[JI)V+92
j  sun.font.GlyphList.mapChars(Lsun/java2d/loops/FontInfo;I)Z+37
j  sun.font.GlyphList.setFromString(Lsun/java2d/loops/FontInfo;Ljava/lang/String;FF)Z+71
j  sun.java2d.pipe.GlyphListPipe.drawString(Lsun/java2d/SunGraphics2D;Ljava/lang/String;DD)V+148
j  sun.java2d.SunGraphics2D.drawString(Ljava/lang/String;II)V+60
j  FontCrasher.tryFont(Ljava/lang/String;)V+138
j  FontCrasher.main([Ljava/lang/String;)V+20
v  ~StubRoutines::call_stub

この場合、特定のフォントがおそらく問題です。その場合は、このフォントをシステムから削除すれば、おそらく問題が解決します。

フォントファイルを特定するには、アプリケーションの実行時に -Dsun.java2d.debugfonts=true を指定します。通常、最後に言及されたフォントが、問題の原因となっているフォントです。典型的な出力の例を次に示します。

INFO: Registered file C:\WINDOWS\Fonts\WINGDING.TTF as font ** TrueType Font: Family=Wingdings
 Name=Wingdings style=0 fileName=C:\WINDOWS\Fonts\WINGDING.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file SYMBOL.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager addToFontList
INFO: Add to Family Symbol, Font Symbol rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager registerFontFile
INFO: Registered file C:\WINDOWS\Fonts\SYMBOL.TTF as font ** TrueType Font: Family=Symbol
 Name=Symbol style=0 fileName=C:\WINDOWS\Fonts\SYMBOL.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager findFont2D
INFO: Search for font: Dialog
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file ARIALBD.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager addToFontList
INFO: Add to Family Arial, Font Arial Bold rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager registerFontFile
INFO: Registered file C:\WINDOWS\Fonts\ARIALBD.TTF as font ** TrueType Font: Family=Arial
 Name=Arial Bold style=1 fileName=C:\WINDOWS\Fonts\ARIALBD.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file WINGDING.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file SYMBOL.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager findFont2D
INFO: Search for font: Dialog
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file ARIAL.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager addToFontList
INFO: Add to Family Arial, Font Arial rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager registerFontFile
INFO: Registered file C:\WINDOWS\Fonts\ARIAL.TTF as font ** TrueType Font: Family=Arial
 Name=Arial style=0 fileName=C:\WINDOWS\Fonts\ARIAL.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file WINGDING.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file SYMBOL.TTF

注 - 場合によっては、最後に言及されたフォントが実際には無実である可能性もあります。フォント名が出力されるのは初回使用時であり、その後の使用では表示されません。


この特定のフォントが問題の原因であることを確認するには、そのフォントをシステムから一時的に削除します。この特定のファミリ名に関連付けられたファイル名は、上の出力から容易にわかります。

もう 1 つの確認方法は、Font2DTest ツール (demo/jfc/Font2DTest) を使って疑わしいフォントをテストすることです。特定のフォントのサイズ、スタイル、およびラスター化モードを指定できます。Font2DTest で特定のフォントを表示させる途中で JDK がクラッシュした場合、そのフォントが、問題の原因となったフォントである可能性が非常に高くなります。

あるフォントが JDK のクラッシュを引き起こしたことがわかった場合、この問題を、特定のフォントとオペレーティングシステムを含めて、bugs.sun.com で報告することが非常に重要です。バグ報告の詳細については、第 8 章「バグレポートの提出」を参照してください。

3.3.2 テキストの外観の違い

Java は独自のフォントラスタライザを備えているため、Java アプリケーションとネイティブアプリケーションとでテキストの外観に何らかの小さな違いがあることが予想できます。

こうした相違点のもっとも典型的な原因の 1 つは、アンチエイリアス設定が違う可能性があることです。特に、Swing アプリケーションは、Linux デスクトップのフォントアンチエイリアス設定を無視する場合があります。

この動作には、考えられる理由がいくつかあります。

構成が予想どおりのものであることを確認する最良の方法は、Font2DTest を実行し、ネイティブアプリケーションで使用されているフォントを明示的に選択し、ほかのパラメータを必要に応じて設定することです。Font2DTest ツールのサンプル画面を次に示します。

Font2DTest ツールのサンプル画面
Font2DTest ツールのサンプル画面

ヒント:ユーザー独自の文字列を入力するには、「Text to use」というラベルの付いたドロップダウンメニューで「user text」を選択します。

Java 言語のフォントのサイズは常に 72 dpi で表現されます。ネイティブ OS では別の画面 dpi を使用できるため、調整が必要になります。対応する Java フォントサイズを計算するには、Toolkit.getScreenResolution() を 72 で割り、その結果にネイティブフォントのサイズを掛けます。

Windows Look & Feel や (Solaris OS および Linux 用の) GTK Look & Feel など、すべての「ネイティブ」Swing Look & Feel で、Swing コンポーネントによってこの調整が自動的に実行されますが、Font2DTest を実行する場合、そのテキスト表示領域では常に 72 dpi が使用されます。

Windows 以外のオペレーティングシステムでの一般的な推奨事項は、Type1 フォントの代わりに TrueType フォントを使用することです。フォントのタイプを確認するもっとも簡単な方法は、ファイル拡張子を調べることです。拡張子 pfapfb は Type1 フォントを示し、ttfttc、および tte は TrueType フォントを表します。

3.3.3 メトリックス

テキストの境界が予想していたものと異なることに気づいた場合、境界の適切な計算方法を使用していることを確認してください。たとえば、FontMetrics から得られる高さは特定のテキストに固有のものではなく、stringWidth は論理的な有効幅を示し、「幅」と同じものではありません。詳細については、Java 2D FAQ の、フォントやテキストの質問に関するセクションを参照してください。

3.4 Java 2D 印刷

このセクションでは、Java 2D 印刷で発生する可能性のあるいくつかの問題を説明し、その原因と解決方法を提示します。

Java 2D FAQ の印刷の質問に関するセクションも参照してください。

問題:Windows で、印刷中に JRE がクラッシュします。

原因: JRE が使用する Windows プリンタドライバに問題がある可能性があります。

解決方法: 使用中のプリンタの Windows プリンタドライバをアップグレードします。

問題:Windows で、印刷が成功したようにみえるのにジョブが印刷されません。

原因: 一部のジョブでは、プリンタへのスプールが正しく行われません。

解決方法: プリンタドライバのプロパティーで、「高度な印刷のオプション」を無効にします。

問題:Windows で、印刷ダイアログが表示されるまでに長い時間がかかります。

原因: アプリケーションが、切断されているプリンタも含め、すべてのプリンタを JRE にプローブさせている可能性があります。

解決方法: 切断されているか到達不可能なネットワークプリンタを探し、それらをプリンタのリストから削除します。

問題:Solaris OS および Linux で、PrinterJob.printDialog() によって「サービスが見つかりません」というエラーが表示されます。

原因: 原因は次のいずれかです。

  • lpc ユーティリティーが /usr/sbin ディレクトリにありません。

  • lpstat ユーティリティーが /usr/sbin ディレクトリにありません。

解決方法: lpclpstat を、上で言及した標準の場所にインストールします。