2.9 オペレーティング・システム・リソースの管理について
オペレーティング・システムのリソースは、どのコンピュータでも制限されています。Javaは、プログラミング言語であると同時に、コンピューティング・プラットフォームの提供を目指しているため、プラットフォームに依存しないクラス、およびプラットフォーム固有のリソースにアクセスするためのフレームワークが用意されています。Javaのクラス・メソッドはJVMを介してオペレーティング・システム・リソースにアクセスします。Javaのこのモデルには潜在的な問題があり、これは、ガベージ・コレクタが管理するのはJavaオブジェクトで、そのJavaオブジェクトが保持するオペレーティング・システム・リソースではない場合に、プログラマが全リソースの管理をそのガベージ・コレクタに委任することに起因しています。
さらに、共有サーバーを使用している場合、Javaオブジェクト内に保持されているオペレーティング・システム・リソースは、1つのセッションの複数のコールにわたって保持されると無効になる可能性があります。
次の各項では、これらの問題について説明します。
2.9.1 オペレーティング・システム・リソースの概要
オペレーティング・システム・リソースへのアクセス
デフォルトでは、Javaユーザーはオペレーティング・システムの大半のリソースに直接アクセスできません。システム管理者は、JVMセキュリティ制限を変更することで、オペレーティング・システムのリソースにアクセスするパーミッションをユーザーに付与できます。JVMセキュリティは、Java 2セキュリティに準拠したシステム・リソースで施行されます。
オペレーティング・システム・リソースの存続期間
オペレーティング・システム・リソースへのアクセスには、標準のコアJavaクラスとメソッドを使用できます。リソースにアクセスした後、そのリソースがアクティブである期間は、リソースの種類によって異なります。メモリーはガベージ・コレクションされます。専用モードのサーバーを使用している場合、ファイル、スレッドおよびソケットは、複数コールにわたって存続します。共有サーバー・モードでは、ファイル、スレッドおよびソケットはコール終了時に終了します。
2.9.2 ガベージ・コレクションとオペレーティング・システム・リソース
メモリーがJavaオブジェクト・メモリーとオペレーティング・システムの構成メンバーの2つの領域に分割されているとします。Javaオブジェクト・メモリー領域にはすべてのオブジェクトと変数が含まれています。オペレーティング・システムの構成メンバーには、オペレーティング・システムが要求に応じてオブジェクトに割り当てるリソースがあります。これらのリソースにはファイルやソケットなどが含まれます。
基本的なプログラミング規則では、Javaオブジェクトとオペレーティング・システム構成メンバーの両方のメモリーをクローズするように規定されています。Javaプログラマは、ガベージ・コレクタによってメモリーが解放されると誤解することがあります。ガベージ・コレクタは、未使用のJavaオブジェクト・メモリーを収集するために作成されました。ただし、オペレーティング・システムの構成メンバーはクローズされません。オペレーティング・システムの構成メンバーは、Javaオブジェクトをガベージ・コレクションする前にプログラムでクローズする必要があります。
たとえば、オブジェクトがファイルをオープンするたびに、オペレーティング・システムはそのファイルを作成してオブジェクトにファイル・ハンドルを割り当てます。ファイルがクローズされないと、オペレーティング・システムはコールの終了またはJVMの終了までファイル・ハンドルの構成メンバーを保持します。そのため、これらの構成メンバーが不足する可能性があります。各オペレーティング・システムのハンドルは無限ではありません。ハンドルの不足を回避するには、メソッドを終了する前にリソースをクローズします。ソケットに連結されたストリームについてもソケットをクローズする前にクローズします。
パフォーマンス上の理由から、ガベージ・コレクタは各オブジェクトにハンドルがあるかどうかを確認できません。したがって、ガベージ・コレクタはJavaオブジェクトおよび変数を収集しますが、ハンドルを解放するための適切なオペレーティング・システム・メソッドは発行しません。
例2-4に、オペレーティング・システムの構成メンバーのクローズ方法を示します。
inFile
をクローズしない場合、File
オブジェクトは最終的にはガベージ・コレクションされます。File
オブジェクトがガベージ・コレクションされても、ファイルがクローズされていないため、オペレーティング・システムでは、そのファイルが使用中と判断されます。
注意:
リソースをクローズするために、Javaファイナライザを使用することが必要な場合もあります。ただし、ファイナライザではタイムリな実行が保証されません。また、ガベージ・コレクタに時間的な余裕があると、ファイナライザは実行するためにキューに挿入されます。ファイナライザ内のリソースをクローズすると、JVMが終了するまでリソースが解放されない可能性があります。メソッドの中でリソースをクローズすることが最も確実な方法です。
例2-4 オペレーティング・システム・リソースのクローズ
public static void addFile(String[] newFile) { File inFile = new File(newFile); FileReader in = new FileReader(inFile); int i; while ((i = in.read()) != -1) out.write(i); /*closing the file, which frees up the operating system file handle*/ in.close(); }