このページで解決しない高度なJavaのシステム障害はJaTSにお任せください

Trouble 19: ヒープサイズが予期しない大きさになります



<Q19-1>ObjectOutputStream使用中にヒープ使用量が上がりつづけてしまいます。


<発生環境>
OS Windows/Linux
JDK JDK1.3.1
Vender Sun
<A19-1>
ObjectOutputStream.writeObject()するとObjectOutputSream内に書き込まれたオブジェクトとそのオブジェクトが保持しているオブジェクトの参照がObjectOutputSream内にキャッシュとして保持されます。
この仕組みのため、自分のプログラムでは参照を開放したはずのオブジェクトがガベージコレクションの対象にならず、メモリを圧迫する場合があります。
ObjectOutputSreamを使用する場合はストリームを開いたままにせずに、適切なタイミングで閉じるか、ObjectOutputStream.reset()を呼び出してObjectOutputSreamが保持するオブジェクトの参照を開放する必要があります。
Page Top

<Q19-2>Listのclear()を呼んでも空きヒープ領域が増えません。

空きヒープ領域を増やすために不要なListをclear()メソッドで開放しても、すぐには空きヒープ領域が増えません。

<発生環境>
OS Any
JDK Any
Vender Any
<A19-2>
Listのclear()メソッドはListが持っている参照を削除するだけであり、参照先のオブジェクトを破棄するわけではありません。そのため空きヒープ領域はすぐには増えません。

ガベージコレクトの実行により、参照先オブジェクトが使用していたヒープ領域が開放されます。

以下のサンプルを参照して下さい。
import java.util.*;

public class ListSample
{
  public static void main(String[] args)
  {
    //プログラム開始時の空きヒープ領域を調べる。
    Runtime rt = Runtime.getRuntime();
    System.out.println( "\n<空きヒープ領域>\n");
    System.out.println( "プログラム開始時\t: " + rt.freeMemory() );

    //リストに格納するオブジェクトを用意する。
    String[] bigObj = new String[100000];
    for(int i=0; i<bigObj.length; i++)
    {
      bigObj[i] = "Now making a BIG object!!";
    }

    //オブジェクト作成後の空きヒープ領域を調べる。
    System.out.println( "オブジェクト作成後\t: " + rt.freeMemory() );

    //リストにオブジェクトを格納する。
    ArrayList testList = new ArrayList();
    for(int i=0; i<bigObj.length; i++)
    {
      testList.add( bigObj[i] );
    }

    //リスト作成後の空きヒープ領域を調べる。
    System.out.println( "リスト作成後\t\t: " + rt.freeMemory() );

    //リストからオブジェクトを削除する(ここでは参照が削除されるのみ)。
    testList.clear();

    //clear()呼び出し後の空きヒープ領域を調べる。
    System.out.println( "clear()呼び出し後\t: " + rt.freeMemory() );

    //ガベージコレクトを実行する。
    System.gc();

    //gc()呼び出し後の空きヒープ領域を調べる。
    System.out.println( "gc()呼び出し後\t\t: " + rt.freeMemory() );
  }
}
以下に実行結果を示します。

>java ListSample
      
<空きヒープ領域>
      
プログラム開始時        : 1757600
オブジェクト作成後      : 1357176
リスト作成後            : 594456
clear()呼び出し後       : 594136
gc()呼び出し後          : 1316264
clear()メソッドではヒープ領域の状態はほとんど変わらず、ガベージコレクトの実行後、空きヒープ領域が増えたことが分かります。

ただしgc()メソッドはJavaVMによっては実行されないことがあるので注意が必要です。
Page Top

<Q19-3>tomcatの起動シェルでは起動オプションを指定していないのに、環境ごとに最大ヒープサイズが変わります。

環境A:
マシン : Sun Fire V490
メモリ : 8GB
CPU : ×4
⇒serverモード,最大ヒープサイズ=1024M

環境B:
マシン : Sun Fire V210
メモリ : 4GB
CPU : ×1
⇒clientモード,最大ヒープサイズ=64M

環境C:
マシン : Sun Fire V250
メモリ : 2GB
CPU : ×2
⇒serverモード,最大ヒープサイズ=512M

<発生環境>
OS Any
JDK 5.0
Vender Sun
<A19-3>
tomcatに限った話ではありません。

J2SE 5.0から、サーバクラスマシンでは、最大ヒープサイズが、物理メモリの1/4と、1GBの小さい方に自動で設定されるためです。
サーバクラスマシン以外では、最大ヒープサイズは64MBになります。

※サーバクラスマシンとは、少なくとも2つのCPUと、最少でも2GBの物理メモリを備えているマシンのことです。

例)
環境Aはサーバクラスマシンであり、物理メモリの1/4(2GB)>1GBであるため、最大ヒープサイズは1G(1024M)に設定される。

参照URL:
http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/vm/server-class.html
http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/vm/gc-ergonomics.html
Page Top

注意:本文書の内容に誤りがあり、またこの文書によって不利益を被っても、
Acroquest Technology 株式会社は一切関知いたしません。

  • 現象別Index
  • 原因別Index

Find Bugsバグ詳細

Find Bugs Bug Descriptions日本語版

RSSで更新情報を取得する

RSSとは、ホームページの更新情報を配信する為のフォーマットです。
RSSを利用すると、登録したページの情報が更新された場合に、更新情報を自動的に受け取る事ができます。

詳細

弊社小森が執筆致しました

Javaでオブジェクト指向開発

Javaプログラミング言語習得において、新人プログラマーの最初の障害は「オブジェクト指向の壁」です。
本書は、Javaのソフトウェア開発を中心に事業を発展させてきたAcroquest社の新人教育セミナーを加筆・書籍化したもので、大卒の新人に対して、ゼロからJava言語を教えてきた実績をフィードバックしています。

メールマガジン配信中

Javaトラブルシューティングのメルマガをはじめました!是非ご購読ください

詳細