[Seasar-user:1688] S2.1系の OutOfMemoryError について

Sadanori ITO sito_dev
2005年 3月 27日 (日) 21:56:42 JST


伊藤 (sito) です。

S2 の 2.2 系がリリースされて個人的には解決済みの問題なのですが,何らかの
理由で現在も 2.1 系を利用されている方のためにご報告しておきます。

2.1(CGLIB 版)から 2.2(Javassist 版)に変更されることになった理由である
パフォーマンスの問題と根本の原因は同じと思いますが,instance="prototype" を
指定したコンポーネントに aspect を適用した状態で,繰り返し取得し続けると
OutOfMemoryError が発生します。

※検証環境では 2000 回を超えた程度の呼び出し回数で発生。

検証するためのコードを書いただけで,それ以上深く追っていないため,推測に
しかならないのですが,こちらの日記 http://d.hatena.ne.jp/noryksj/20050220
で試されていたように

a. CGLIB が毎回生成される AopProxy.MyCallbackFilter を HashMap に蓄積してしまう
b. ClassLoader が毎回生成される Enhance 済みクラスをロードしたまま蓄積してしまう

のどちらか(あるいは両方)が引き起こしている問題だと思います。

ちなみに Enhance 済みクラスを1度しか作成しない現行版(2.2 系)では,
1000 万回取得してもメモリ使用量は 9MB 程度で安定していました。

現在もダウンロードサイトには旧安定版として(?)目立つ場所に並んでいる
ようなので,2.1 系は 2.1.14 でメンテ終了ということであれば,ユーザの方は
その辺りを認識しつつ運用する必要があるかと思います。

以上ご報告まで。

----- 長くなりますが,以下に検証コードと結果を示しておきます

----- Java コード (OutOfMemory.java) -----

package examples.dicon;

import java.util.Date;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

public class OutOfMemory
{
  private static final String PATH = "examples/dicon/OutOfMemory.dicon";

  public static void main(String[] args)
  {
    S2Container container = S2ContainerFactory.create(PATH);

    for (int i = 1; i <= 10000; i++)
    {
      Date date = (Date) container.getComponent(Date.class);

      if (i % 1000 == 0)
      {
        System.out.println(
          "count " + i + ", date = " + date + ", " + date.getClass());
      }
    }
  }
}

----- Dicon ファイル (OutOfMemory.dicon) -----

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
  "http://www.seasar.org/dtd/components.dtd">
<components>
  <component name="traceInterceptor"
    class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
  <component class="java.util.Date" instance="prototype">
    <aspect pointcut="getTime">traceInterceptor</aspect>
  </component>
</components>

----- 実行環境 -----

Windows XP + J2SDK 1.4.2_07
Linux + J2SDK 1.4.2_07
※結果はどちらも同じでした。

----- S2.2.4 を利用した場合の結果 -----
count 1000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073
count 2000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073
count 3000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073
count 4000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073
count 5000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073
count 6000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073
count 7000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073
count 8000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073
count 9000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073
count 10000, date = Sun Mar 27 19:33:00 JST 2005, class $$java.util.Date$$EnhancedByS2AOP$$1edc073

----- S2.1.14 を利用した場合の結果 -----
count 1000, date = Sun Mar 27 19:34:38 JST 2005, class $java.util.Date$$EnhancerByCGLIB$$5a5b1b4c
count 2000, date = Sun Mar 27 19:35:12 JST 2005, class $java.util.Date$$EnhancerByCGLIB$$f75a0473
net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
     at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:236)
     at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:368)
     at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:280)
     at org.seasar.framework.aop.proxy.AopProxy.create(AopProxy.java:112)
     at org.seasar.framework.container.assembler.AbstractConstructorAssembler.assembleDefault(AbstractConstructorAssembler.java:36)
     at org.seasar.framework.container.assembler.AutoConstructorAssembler.assemble(AutoConstructorAssembler.java:28)
     at org.seasar.framework.container.deployer.PrototypeComponentDeployer.deploy(PrototypeComponentDeployer.java:22)
     at org.seasar.framework.container.impl.ComponentDefImpl.getComponent(ComponentDefImpl.java:72)
     at org.seasar.framework.container.impl.S2ContainerImpl.getComponent(S2ContainerImpl.java:83)
     at examples.dicon.OutOfMemory.main(OutOfMemory.java:18)
Caused by: java.lang.reflect.InvocationTargetException
     at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     at java.lang.reflect.Method.invoke(Method.java:324)
     at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:373)
     at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:218)
     ... 9 more
Caused by: java.lang.OutOfMemoryError

※ OutOfMemoryError も問題ですが,速度もかなり...2.2 があって良かったです。

-- 
s.ito

__________________________________
Do You Yahoo!?
Upgrade Your Life
http://bb.yahoo.co.jp/




Seasar-user メーリングリストの案内