< Tomcat 6 >
All implementations of 
Connector support the following attributes:

emptySessionPath

If set to true, all paths for session cookies will be set to /. This can be useful for portlet specification implementations. If not specified, this attribute is set to false.
A side effect to setting this to true, is that if Tomcat creates a new session it will attempt to use the cookie session id if supplied by the client.


All implementations of Context support the following attributes:

crossContext

Set to true if you want calls within this application to ServletContext.getContext() to successfully return a request dispatcher for other web applications running on this virtual host. Set to false (the default) in security conscious environments, to makegetContext() always return null.

sessionCookiePath

The path to be used for all session cookies created for this Context. If not set, the context path will be used. Note that this will be overridden by the emptySessionPath attribute on the connector used to access this Context.



source - http://tomcat.apache.org/tomcat-6.0-doc/config/http.html
source - https://tomcat.apache.org/tomcat-6.0-doc/config/context.html



< Tomcat 7 >
All implementations of Context support the following attributes:

crossContext

Set to true if you want calls within this application to ServletContext.getContext() to successfully return a request dispatcher for other web applications running on this virtual host. Set to false (the default) in security conscious environments, to make getContext() always return null.

 sessionCookiePath

The path to be used for all session cookies created for this context. If set, this overrides any path set by the web application. If not set, the value specified by the web application will be used, or the context path used if the web application does not explicitly set one. To configure all web application to use an empty path (this can be useful for portlet specification implementations) set this attribute to / in the global CATALINA_BASE/conf/context.xml file.

Note: Once one web application using sessionCookiePath="/" obtains a session, all subsequent sessions for any other web application in the same host also configured with sessionCookiePath="/" will always use the same session ID. This holds even if the session is invalidated and a new one created. This makes session fixation protection more difficult and requires custom, Tomcat specific code to change the session ID shared by the multiple applications.


source - http://tomcat.apache.org/tomcat-7.0-doc/config/context.html





[Java Web Application간에 Cross Context에 대한 고찰]

서블릿 웹컨테이너인 Tomcat에 두개의 서블릿(각각 Bar,Foo라고 하죠.)을 올려놓고 Bar, Foo간에 통신하려면 가장 쉽게 생각할 수 있는게 Socket을 연결해주거나 Http로 통신하는 방법이 있을겁니다.


그런데 생각해보면 하나의 컨테이너에 올라온 서블릿이라면 톰켓 설정에 crossContext=true으로 컨텍스트간 참조할 수 있도록 해주면 메모리 내에서 통신이 가능해집니다. 즉, Foo가 Bar의 컨텍스트를 가져와 그곳에 정의된 클래스와 메소드를 리플렉션으로 invoke가 가능하다는 의미입니다. 이때 해당 메소드에 인자를 주면 반환값을 얻어올 수 있죠. 마치 직접 함수를 호출해주는 거죠. 이렇게 하면 Socket 연결비용이나 http 통신비용이 전혀 없지 그저 java객체간 호출정도이기 때문에 성능상 훨씬 이득입니다.


다만, 서블릿간 통신시 각 서블릿내에 정의된 커스텀 클래스로 캐스팅하는 문제가 있습니다. 좀 더 풀어보자면, Foo와 Bar에 동일한 com.cookilab.lib.Person 클래스를 정의했다고 가정하죠. 이건 공용라이브러리로 올린 것도 아니고 Foo, Bar에 각각 static하게 메모리를 먹습니다. 이 경우 Foo가 Bar에 메소드에 Person객체를 인자로 전달하던가 반환으로 받으려 하면 캐스팅문제에 봉착합니다. 왜냐하면 동일한 패키지와 클래스 명이라고 하더라도 각각의 서블릿 메모리상에 올라간 정적 클래스이기 때문에 전혀 다른 클래스인거죠. 그래서 캐스팅이 불가합니다.


http://blog.imaginea.com/cross-context-communication-betwe…/


위 글은 이 문제를 Adaptor를 통해 해결을 보고 있습니다. 여기서 안내하는 방법은 통신비용은 위에서 소개한 대로 동일하게 톰켓의 context공유로 해결하고 다만 데이터 교환은 json으로 합니다. 이때 중간에 adaptor를 둬서 json을 상대 서블릿에 있는 ObjectMapper로 Person객체로 인코딩, 디코딩하는 겁니다.
하지만 기왕에 하는 인메모리 통신인데.... json 인코딩/디코딩이라니요.... ㅡㅡ


이 방법이 아니라 캐스팅 문제를 근본적으로 해결하기 위해서는 결국 서블릿 컨테이너의 공유 라이브러리에 커스텀 클래스(com.jidolstar.myweb.Person)를 올려놓고 Foo와 Bar가 이 클래스를 참고하는 겁니다. 이렇게 하면 클래스 정의가 하나의 메모리를 참조하므로 캐스팅문제가 발생하지 않을겁니다.


뭔가 이렇게 하면 Spring Framework나 각종 라이브러리도 공유해서 쓰면 좋지 않을까 생각됩니다. Foo와 Bar도 가벼워 져서 좋을지도 모르겠다는 생각이 들었습니다.


문제는 Java의 경우 이러한 개발이 여유치 않은 것 같습니다. 많은 책이나 레퍼런스를 보면 공유 라이브러리화 해서 처리하는 것에 대한 기술적 문서가 거의 전무한 것 같습니다. 결국 이것은 이러한 방식으로 하는 것은 Java 서버 프로그램에서는 권장하지 않는 것 같습니다. 하지만 이론적으로는 당연하게도 되거든요. 톰켓은 원래 이걸 지원해줍니다. 당연하게도 자바전체나 톰켓라이브러리전체가 각 서블릿이 컴파일될때 함께 컴파일되는것은 아니지 않겠어요? ^^ 문제는 Spring은 이러한 방식으로 써도 잘 동작할 수 있도록 설계가 되어있는지 전혀 모른다는 점입니다. DI만 생각해도 공유 라이브러리화 해서 제대로 동작할지도 알 수 없습니다.


암튼 Java쪽에 대한 정확한 지식 부족으로 여기까지만 하고 결국 Foo와 Bar는 없는 것으로 하고 하나의 서블릿으로 통합하게 되었습니다. Java 고수님들은 이 부분에 대해서 어떻게 생각하시고 혹시 좋은 해결방법이 있는지 궁금하네요. 개발환경 및 배포환경 전반적으로 의견을 듣고 싶네요.




출처 - https://www.facebook.com/cookilab/posts/918200161570126







Cross-Context Communication between Web Applications 9


The Problem Scenario:

In one of our assignments, we faced a problem in making communication between two different spring based web applications which are in the same web container. Let us explain it with an example; say there are two web applications ‘Foo’ and ‘Bar’ deployed in the same web container and ‘Foo’ depends on ‘Bar’ to access a method say ‘barMethod()’ of ‘BarService’ ( a Java Class present inside the ‘Bar’ application), then

  • The ‘Bar’ application servlet must provide a method to access its Java classes
  • The ‘Foo’ application must get the response from Bar application through HTTP.

Problem#1: Though both the applications reside inside the same container and ‘Foo’ application knows what method of the Java class of ‘Bar’ application it has to access, it has to go through the network using HTTP protocol as if ‘Foo’ application request is considered as a client request to ‘Bar’ application as shown in the figure. Is there an optimal way to avoid the HTTP protocol overhead?



Foo-Bar communication with out Adapter

Problem#2: Say a client (web, mobile etc..) invokes ‘fooMethod()’ of ‘FooService’ which internally calls ‘barMethod()’ of ‘BarService’ through ‘FooServlet’. And say the transaction involved in ‘Foo’ succeeds and the transactions involved in ‘Bar’ fails, then the first transaction gets committed and the second gets rolled-back as the participating threads are different. It means that according to the client, the participating transactions are not atomic as they get partially committed. Is there a way to make them atomic?

The Solution:

Yes..The solution what we found is to use an ‘adapter’ code in a cross-context enabled web container as shown in the figure, which would help in solving both the problems discussed.



Foo-Bar communication With Adapter
  • Enabling cross-context:

Cross-Context is a feature provided by web containers and enabling configuration varies from container to container. For example, in Tomcat, the ‘crossContext’ attribute in ‘Context’ element of ‘TOMCAT_HOME\conf\context.xml’ must be set to true, to enable cross-context communication as shown below. By enabling this, one web application can get access to other web application.

________________________________________________________________

<Context crossContext="true">     
<!-- Default set of monitored resources -->
     
<WatchedResource>
WEB-INF/web.xml</WatchedResource> 
</Context>
________________________________________________________________

  • The Adapter:

Once the ‘Bar’ context is obtainable in ‘Foo’, we can easily get the ‘Bar’ application spring beans using which we can access the ‘barMethod’. Yes!. That’s exactly is what the adapter does. Let us see how to invoke the ‘barMethod’ from ‘Foo’ context in two different sections. The first section explains the adapter functionality if the method invocation involves only simple data types (like int, float, String) as the method arguments/ return type and the second section explains the adapter functionality if the method invocation involves custom data types like (Person, Address etc…).

Handling Simple Data Types

The adapter does the following, before accessing any of the ‘Bar’ application Java classes (‘BarService’),

  • Saves the current class loader (which loaded the ‘Foo’ application) in a temporary variable
  • Sets the current class loader to the one which loaded the ‘Bar’ web application.
  • Resets the current class loader with the one we saved in the temporary variable once it has finished accessing the Java Class of ‘Bar’ application.
  • Let us see the adapter code.

___________________________________________________________________________________________

 String methodName = request.getParameter(WEBConstants.PARAM_METHOD);
 ServletContext srcServletContext = request.getSession().getServletContext();
 ServletContext targetServletContext = srcServletContext.getContext("/Bar");

//save the class loader which loaded the 'Foo' application in a variable
 ClassLoader currentClassLoader = Thread.currentThread().
                                             getContextClassLoader();

 try {
   Object object = targetServletContext.getAttribute
         ("org.springframework.web.servlet.FrameworkServlet.CONTEXT.bar");

// get the class loader which loaded the 'Bar' application
   ClassLoader targetServiceClassLoader = object.getClass().getClassLoader();

// and set it as the current context class loader.
   Thread.currentThread().setContextClassLoader(targetServiceClassLoader);

   Class<?> classBarService = (Class<?>) targetServiceClassLoader.loadClass
                            ("com.pramati.crosscontext.service.BarService");

   Method getBeanMethod = object.getClass().getMethod
                                   ("getBean", String.class);

// Get the barService defined in the 'Bar' application context.
   Object barService = getBeanMethod.invoke(object, "barService");

// Get the method of the 'barService'
   Method targetMethod = classBarService.getMethod(methodName,
                                              (Class[]) null);

   if (targetMethod == null){
        response.getWriter().println(
                "Error: The method['" + methodName + "' does not exist" );
        return null;
   }
// Invoke the method on 'barService'
   Object responseFromBarMethod =
                    targetMethod.invoke(barService, (Object[]) null);
  } catch (Exception e) {
        e.printStackTrace();
  } finally {
        Thread.currentThread().setContextClassLoader(currentClassLoader);
  }

_______________________________________________________________________

If we do not have these steps done, then we end up in getting ‘ClassCastException’ though we cast the right object with right type. Why? It is simple, the class loaders which loaded the ‘Foo’ application and ‘Bar’ application are different.

Handling Custom Data Types

Are there any changes if we need to pass custom type (Person/ Address etc..) parameters while invoking the method on the other context?. Absolutely Yes; we have changes to be made. There are two ways to fix this scenario.

Solution-1: If we could externalize the custom data type classes which are accessed by multiple web applications (here accessed by ‘Foo’ and ‘Bar’) to a different library and place it inside the commons library location of the web container (In case of tomcat, it is <TOMCAT_HOME>\lib), then we can pass the parameters as we did for simple data types without any source code modification.

Solution-2: If we can not externalize the common custom types then the custom data type objects which are going to be used as parameters must be serialized and deserialized say using JSON JavaScript Object Notation (or XML etc..). By including the below snippet to the adapter, we can do it.

___________________________________________________________________________________________

 Person person = new Person(1, "Kayal");
 ObjectMapper jacksonMapper = new ObjectMapper();

// serialize the param 'Person' with the 'Foo' application jacksonMapper
 String serializedPerson = jacksonMapper.writeValueAsString(person);

 Class<?> classPerson = (Class<?>) targetServiceClassLoader.loadClass
                                ("com.pramati.crosscontext.model.Person");

// Get the jacksonMapper defined in the 'Bar' application context.
 Object targetJacksonMapper = getBeanMethod.invoke(object, "jacksonMapper");

//Get the 'readValue' method of the 'Bar' application's jacksonMapper
 Method readValueMethod = targetJacksonMapper.getClass().getMethod
                             ("readValue", String.class, Class.class);

//Deserialize Person using 'readValue()' of the 'Bar' application's jacksonMapper
 Object deserializedPerson = readValueMethod.invoke(targetJacksonMapper,
                               serializedPerson, classPerson);

// invoke 'barMethodWithParam' of 'BarService' with the deserialized Person
 responseFromBarMethod = targetMethod.invoke(barService,  new Object[]
                                            { deserializedPerson});

// Get the 'writeValueAsString' method of the 'Bar' application's jacksonMapper
 Method writeValueAsStringMethod = targetJacksonMapper.getClass().
                               getMethod("writeValueAsString", Object.class);

//serialize response using 'writeValueAsString' of 'Bar' appln's jacksonMapper
 responseFromBarMethod = (String) writeValueAsStringMethod.invoke
                               (targetJacksonMapper, responseFromBarMethod);
___________________________________________________________________________________________

With this,

  • Able to improve performance by avoiding the HTTP protocol overhead.
  • Able to achieve atomicity in transactions.

How? The transactions are cached by the Spring Tx. Manager using ‘Thread Local’ concept which are specific to threads. If we have communication between applications using the adapter, the threads and the participating transactions are same; hence is atomic.




출처 - http://blog.imaginea.com/cross-context-communication-between-web-applications/








tomcat7 context 간 세션 공유 질문 드립니다. (스프링 시큐리티)


안녕하세요. 스타입니다.

스프링 시큐리티 세션 공유에 대한 해결이 되지 않아 많은 자료를 찾아 보다가 답을 찾을 수 없어서 질문 드립니다.

2개의 웹프로젝트이고, web.xml을 각각 가지고 있고
1개의 서버이고, 도메인은 같고 컨텍스트 루트는 각각 /xxx, /yyy 입니다.

세션 공유를 하기 위해 톰캣의 context.xml에 crossContext="true" 옵션을 붙이기도 시도 해 보았는데, 공유가 되지 않았고,

web.xml에 JSESSIONID를 같게 설정 해보았으나, 
/xxx/ 에서 로그인을 성공하고, /yyy/ 경로로 이동하면
로그인 된 것마저 로그아웃 되어 버리네요.

<session-config>
<cookie-config>
<path>/</path>
</cookie-config>
</session-config>


만일 톰캣 클러스터링을 사용한다고 하면, 
같은 주소를 가지고 있는데 어떻게 할 수 있을까요?

도움을 요청 드립니다. 지금 새벽 3시 ㅜ.ㅜ

tomcat 6 이라면 Connector 의 emptySessionPath 속성
http://tomcat.apache.org/tomcat-6.0-doc/config/http.html 

tomcat7 이면 context 의 sessionCookiePath 속성
http://tomcat.apache.org/tomcat-7.0-doc/config/context.html 

쪽을 확인해 보세요





출처 - http://w.okjsp.pe.kr:8080/article/271281








톰캣 context 간의 세션 공유 문제


안녕하세요.
검색을 해도 개념이 잡히지 않아 도움을 청하게 ?습니다...

서버가 단 1대이고 apache 2.2.3 + tomcat 6을 사용해 서비스되고 있습니다.

tomcat 1대에 내에

<Host name="www.test.com">
<Context docBase="/data/test" path="" processTlds="false" reloadable="false" />
<Context docBase="/data/test1" path="/test1" processTlds="false" reloadable="false" />
</Host>

<Host name="m.test.com">
<Context docBase="/data/mtest" path="" processTlds="false" reloadable="false" />
<Context docBase="/data/mtest1" path="/mtest1" processTlds="false" reloadable="false" />
</Host>

이런식으로 host가 2개 등록되어 있고 
각 host 별로 context가 2개 씩 등록되어 있을 경우

01 각 host 내 context 간의 세션 공유
02 host와 host 간의 context 간의 세션 공유

세션을 공유하게 하려면 어떤 방법을 써야 하는지 여?고 싶습니다..(__)

세션 클러스터링의 개념이 정확히 잡히질 않아서
context간의 세션 공유인지 아니면 was가 여러대일 경우의 was간의 공유를 말하는 건지...
또 was 여러대라면 각 was 별로 위와 같이 host 내 context가 다중 일 경우 세션 공유가 어떻게 되는지..

좀 더 검색해 보고 스스로 답을 찾아야 하는데 
질문하는게 참 죄송스럽습니다.

1번은 설정파일에서
crossContext="true"
emptySessionPath="true"
로 해결하시면됩니다.




출처 - http://okky.kr/article/257887









tomcat6 기준이다.

tomcat7에서는 TEST를 해 보지 못했다.




context 구조는 

webapps/project_a

             /project_b



1. 환경 설정

1.context.xml

<Context crossContext="true">

    <Manager pathname="" />

</Context>


2.server.xml

<Connector port="8080" protocol="HTTP/1.1" emptySessionPath="true" connectionTimeout="20000"                 redirectPort="8443" />

2. session 저장 및 호출하기
1. project_a의 session에 저장
session.getServletContext().setAttribute(session.getId(),"박재혁");

2. project_b에서 project_a의 session에 저장한 값 불러오기
HttpSession session = request.getSession();
ServletContext ctx = request.getSession(false).getServletContext().getContext("/project_a");
String name = (String) ctx2.getAttribute(session.getId());



출처 - http://www.jhpark.or.kr/316







하나의 톰캣에 Context가 여러개 추가된 경우에 세션관련 궁금한 점


안녕하세요,, 톰캣 설정을 하다가 궁금한 점이 있어서 질문 올립니다.

하나의 톰캣에 context가 2개 이상 있는 경우에 
context 사이에는 서로 세션공유가 안된다고 되어있습니다.

좀 엉뚱하지만 여기서 궁금한 점이 있어서요..

브라우져와 서버사이의 http통신시 세션 유지는 jsessionid 쿠키값으로 연결되어 있다고 알고 있습니다.  또 쿠키값은 도메인에 따라 관리되는 것으로 알고 있는데요..

그렇다면 하나의 톰캣에 다음의 두 컨텍스트가 있을때http://is.question.kk/ProjectA

도메인이 is.question.kk 으로 같으므로 쿠키가 공유되지 않나요?
쿠키값은 도메인별이지 컨텍스트별로 공유되는게 아니니까..??(맞죠??--;;)
그렇다면 jsessionId는 어떻게 다른 두 컨텍스트에서 별도로 관리되는건지 궁금합니다.

쿠키와 세션 ... 서버..컨텍스트..통합적으로 생각되지 않네요..
아시는 분 답변 부탁드립니다.

감사합니다.


감사합니다. 
쿠키가 url 패스에 따라 생성될수가 있네요.
아마 톰캣에서 jsessionId를 생성할때 context path에 따라 생성하나봐요?ㅎ


출처 - http://okky.kr/article/218240



I have been looking at solutions for sharing session data between mutliple war files. I came across the following solution http://www.fwd.at/tomcat/sharing-session-data-howto.html

The basic idea of it is that if you have more than one war file, you can set a cookie using the sessionid of the first context that is used.

The cookie can be set using a path that will apply to all contexts/applications.

For example, if i have the following configuration for 3 applicatons

/myapp/app1
/myapp/app2
/myapp/app3

I can set a cookie as follows

/myapp sessionid.

The sessionid cookie will then be sent to any request with /myapp in the address. This allows the session id to then be used by any of the contexts.

The only problem with this approach is that it was written in 2003 and tested on Tomcat 4.

What are your opinions of this approach? Is there a better way of doing it?

Thanks


That article is indeed heavily outdated.

On Tomcat 5.5 and 6.0 you can just set emptySessionPath attribute to true in the <Connector>element in /conf/server.xml.

<Connector ... emptySessionPath="true">

On Tomcat 7.0 this has changed because this is now configureable from the Servlet 3.0 API on. It's then on Tomcat's side configureable by setting sessionCookiePath to / in <Context> element in any responsible context.xml file.

<Context ... sessionCookiePath="/">

As said, there's a new Servlet 3.0 API which allows you to configure the session cookie through the standard API. You can do it either declaratively by adding the following to the web.xml:

<session-config>
    <cookie-config>
        <path>/</path>
    </cookie-config>
</session-config>

or programmatically by SessionCookieConfig which is available by ServletContext#getSessionCookieConfig().

getServletContext().getSessionCookieConfig().setPath("/");

You could do this in ServletContextListener#contextInitialized() or HttpServlet#init().

See also:


source - http://stackoverflow.com/questions/9436736/sharing-session-data-between-contexts-in-tomcat






안녕하세요..

JSP로 웹개발중인 초보 jsper 입니다..^^;;

 

다름이 아니오라 5일째 해결책을 찾아 보다 여기까지 오게 되었습니다..

너무너무 궁금하고 해결도 안되고해서 실례하지만 여쭤봐도 될런지요..

구현 방법은 보통 입문 책에서 소개되는 세션 방법입니다.

Struts나 Spring으로 구현한건 아닙니다.

 

현재 폴더가 두개로 나눠 있습니다

 

폴더1

Login/login.jsp, Login/list.jsp

 

폴더2

Board/list.jsp

 

이렇게 다른 폴더에 두개로 나뉘어 있습니다.

 

설명을 드리자면..

Login/login.jsp 에서 세션을 session.setAttribute("MEMBERID", mid); 이렇게 생성을 했습니다.

Login/list.jsp 에서 세션을 String memberid_session =  (String)session.getAttribute("MEMBERID"); 로 받았습니다.

여기까지는 별 문제없이 세션을 주고 받았습니다.

 

그런데

Board/list.jsp 에서 세션을 String memberid_session =  (String)session.getAttribute("MEMBERID"); 으로 받았을때

null로 받아지게 됩니다.

 

제 개발컴에서는 문제없이 값이 받아지는데 운영서버로 업로드해서 부르면 null로 나옵니다.

찾다보니 별의별 방법이 다 있었는데 어떤걸 해봐도 null로 나옵니다.

그래서, 마지막으로 찾은 방법이 톰캣 server.xml에 먼가를 추가하는 부분이 있더라구요..

 

아래 방법은 찾아본 방법입니다.

<Context path="/Login" docBase="C:/tomcat/webapps/Login" debug="0" reloadable="true" crossContext="true"/>

<Context path="/Board" docBase="C:/tomcat/webapps/Board" debug="0" reloadable="true" crossContext="true"/>

 

위와 같이 crossContext로 두 폴더간의 request를 주고 받을 수 있다고 합니다.

 

운영서버라 적용시켜보기전에 함 여쭤 보고 싶어서 질문을 드립니다..

바쁘시더라도 조금만 시간을 내주셔서 가르침을 주시면 감사하겠습니다.


덧글 2개 | 태그 4개 | 관련글보기
 GoodBug
 (0)  (0)

crossContext를 적용하기 전에 몇가지만 확인해 보세요

 

첫번째로..

도메인이 www.domain.com 이고 이서버의 아이피가 100.20.20.2 이렇다면..

www.domain.com/Login/login.jsp 에서 맺은 세션은 100.20.20.2/Login/list.jsp 에서 인식하지 못합니다

즉 세션을 맺은 요청 url 끼리만 세션이 통합니다

login.jsp에서 세션을 맺은 후 Board/list.jsp 로의 이동이 어떻게 되느냐에 따라 세션이 사라질 수도 있습니다

서브도메인도 마찬가지고요..

 

두번째로..

프로그램 로직을 다시 한번 체크해 보세요

세션을 맺은 후 Board/list.jsp로 갈 때 혹시 세션을 삭제하는 로직이 포함되어 있는지(include등) 말입니다

 

제가 볼때는 crossContext는 최후의 방법이구요..

아마 이것을 사용한다 하더라도 안될 가능성이 더 많은것 같네요

 

나중에 해결되시면 꼭 알려 주세요 ^^;

 

   211.189.124.***2008-03-19 12:55:13
 곱슬대마왕
 (0)  (0)

톰캣에 Host name 설정을 하라고 부탁했더니 이걸 IP로 해 놨네요..ㅎ
전 Domainname으로 들어갔구요..

그래서, 그런 오류가 발생했었습니다.. 감사합니다..

주신 답변으로 해결을 한것 같습니다..

감사합니다..^^

   222.237.189.***2008-03-19 15:35:58

Posted by linuxism
,

GC Log 란 ?

Development/Java 2012. 2. 2. 06:22

안녕하세요. 이번 시간에는 지난 시간에 이어 "GC Log 란 ? #2" 편으로 IBM 계열의 Java 메모리 구조, GC 동작 방식, GC 알고리즘 종류에 대해 설명드리도록 하겠습니다.


IBM 계열 Java의 Heap 메모리 구조는 기본적으로 One Heap 구조이며, 1.5 버전부터는 Sun 계열과 같이 Generational Heap 구조를 사용할 수도 있읍니다.

One Heap 구조는 Heapbase 라고 하는 Heap메모리의 처음 주소에서 Heaptop 주소까지 확장이 가능하며 가변크기일 경우 현재까지 할당된 부분을 Heaplimit이라고 합니다.

Heapbase ~ Heaptop 까지는 -Xmx 옵션으로 설정되는 값이며, Heapbase ~ Heaplimit 까지는 -Xmx 옵션으로 설정되는 값입니다.

One Heap 구조는 Java 1.4와 1.5에서 그 구조가 조금 바뀌었는데요.

다음은 Java1.4 버전의 One Heap 구조에 대한 그림입니다.




그리고 다음은 Java1.5 버전의 One Heap 구조에 대한 그림입니다.




각 영역에 대한 설명은 다음과 같습니다.

- K Cluster, P Cluster

Pinned Class Object(K Cluster), Pinned Object(P Cluster)가 할당되는 곳으로 Default 1280개의 class     entries가 저장 가능하며, Sun 계열 JVM의 Permanent 영역과 비슷한 역할을 합니다.

K Cluster가 꽉차면 P Cluster에 할당되며 P Cluster가 꽉차게 되면 2kbyte의 새로운 P Cluster가 할당 되는데, 이때 P Cluster 영역이 Heap의 영역에 임의적으로 생성되며 이로 인해 Heap Fragmentation이 발생하기도 합니다.

- Heap

생성된 object들이 저장되는 영역입니다.

- Cache

Cache Allocation을 위한 영역으로 Thread간의 경합을 피하기 위한 THL(Thread Local Heap)과 512byte 이하의 작은 object를 할당하는데 사용됩니다. 여기서 Thread간의 경합이란 실제 이러한 Cache 영역이 없다면 Heap 영역에 대해 object를 할당하기 위해 Heap Lock을 발생시키게 됩니다. 이렇게 되면 Thread들간에 object를 할당하기 이해 Heap에 대한 Lock 경합이 발생하게 됩니다. 이러한 경합을 줄이기 위해 Cache를 이용하여 THL을 두어 해당 Thread가 할당할 수 있는 영역을 별도로 지정하는 것입니다.

- Wilderness OR LOA

Large Object의 할당을 효과적으로 하기 위한 공간으로 주로 64kbyte의 object의 할당에 사용됩니다. 항상 64kbyte 이상의 object가 할당되는 것이 아니라, Heap Fragmentation등의 이유로 Heap영역에 object 할당이 불가능할 경우 64kbyte보다 작은 일반 object들도 할당되기도 합니다.


위에서 살펴본 두버전간 Heap 구조의 차이점은 K Cluster, P Cluster 영역(합쳐서 pinned cluster 영역이라함)이 있느냐 없느냐의 차이입니다.


이렇게 바뀌게된 이유는 pinned object로 인한 Heap Fragmentation 문제에 있습니다.

자, 그럼 여기서 pinned object가 무엇인지 알아 보겠습니다. 

pinned object란 고정된 object라는 것으로 원칙적으로 Java에서 모든 object들은 Garbage Collector를 통해 object의 이동이 가능하도록 되어 있습니다. 그러나 일부 특수한 경우는 Garbage Collector가 이동시키지 못하는 object들이 발생합니다.

예들들어 JNI(Java Native Interface)에서 사용하는 object들은 JNI에서 직접 unpinned 될때까지 고정이 됩니다. 또한 class에 대한 메타 정보들도 고정영역으로 지정됩니다.

이러다 보니 실제 pinned object들은 GC에 의해 compaction 작업이 불가능합니다. 

이러한 이유로 pinned cluster라는 영역을 두어 해당 영역에 pinned object들을 저장하게 됩니다. 

문제는 이러한 pinned cluster 영역 보다 많은 pinned object가 발생하게 되면 pinned object를 저장하기 위해 JVM은 Heap 영역에 pinned object를 위한 공간을 임의로 지정합니다. 이러한 공간이 임시성일 수도 있고 영구적인 공간이 될 수도 있습니다. 

이런 현상(pinned cluster영역이 부족할 경우)이 발생하게 되면 Heap 영역에 한번에 할당할 수 있는 일련된 순서의 메모리가 점점 줄어들게 되어 나중에는 별로 크지 않는 object를 할당할려고 해도 allocation failure(AF)이 발생하게 됩니다.

이러한 현상을 Heap Fragmentation이라고 합니다.

1.5 버전에서는 이러한 문제점을 해결하기 위해 pinned object의 저장을 Java Heap이 아닌 System Heap에 저장하도록 변경하였습니다.

1.4 버전에서 발생하는 Heap Fragmentation 문제는 K Cluster와 P Cluster의 크기를 조정을 통해(-Xk, -Xp 옵션 사용) 해결할 수 있습니다. 

물론 적정 크기 설정을 위해서는 pinned object의 사용을 모니터링(-Dibm.dg.trc.print=st)을 해야 합니다.

적정 값을 찾기 위한 내용은   포스트를 참고하십시요.

 ( http://blog.naver.com/bumsukoh/110113098160 )


다음은 Java 1.5 버전 이상에서 사용할 수 있는 Generational Heap 구조에 대해 알아 보겠습니다.

이 Generational Heap 구조는 Sun 계열 Java의 Generation Heap 구조와 매우 흡사합니다.

단, 이 Generational Heap 구조가 Sun 계열 Java에서는 기본적인 구조이지만 IBM 계열 Java에서는 옵션을 통해 지정할 수 있으며 GC에 대한 Policy 옵션중의 하나입니다.

Generational Heap 구조를 사용하기 위해서는 -Xgcpolicy:gencon 옵션을 사용합니다. 

다음은 Generational Heap 구조에 대한 그림입니다.




각 영역에 대한 설명은 다음과 같습니다.

- Allocation Space

새롭게 생성되는 object가 할당되는 영역이며, Sun 계열 JVM의 Eden 영역이라 할 수 있습니다.

- Survivor Space

Alive object가 저장되는 공간이며, 실제로 Scavenge로 인한 GC 수행 시 live object들이 copy되는 공간입니다. Sun 계열 JVM의 Survivor 영역이라 할 수 있습니다.

- Tenured Space

Nursery 영역에 저장되어 있었던 object 중에 오래된 object가 이동되어 저장되는 영역입니다.


지금까지 IBM 계열 Java의 Heap 구조에 대해 알아 보았습니다.

다음은 IBM 계열의 Java의 GC 동작 방식에 대해 알아보도록 하겠습니다.

One Heap 구조와 Generational Heap 구조에 따라 GC를 처리하는 방식이 다르게 됩니다.


우선 One Heap 구조의 GC에 대한 부분을 알아 보겠습니다.

One Heap 구조의 GC는 Mark -> Sweep -> Compact 단계를 거쳐 GC가 이루어지게 됩니다.

각 단계는 다음과 같은 역할과 특징을 가집니다.


- Mark 단계

모든 live object들에 대한 mark 작업을 수행합니다. 즉 참조계수(Reference count)가 1이상인 object는 mark 되며 나머지는 garbage로 간주됩니다.

mark된 live object는 markbit vector에 주소가 저장됩니다.

Parallel Mark 기능을 사용할 수 있으며, 다수개의 Thread가 Mark 단계를 수행하기 위해 기동됩니다. 이렇게 Parallel Mark를 위해서는 -Xgcthreads 옵션으로 설정이 가능합니다.

또한 GC로 인한 STW(Stop The World) 시간을 감소시키기 위해 Concurrent Mark 기능을 사용할 수 있습니다.

 -Xgcpolicy:optavgpause 옵션 설정을 통해 사용 가능합니다.

Mark 단계를 위한 GC Policy 설정을 위한 옵션의 종류는 4가지가 있으며 다음과 같습니다.

- optthruput

Concurrent mark을 disable 시킵니다. GC로 인해 멈추는 시간에 문제가 없다면(즉, 어플리케이션 수행 응답시간에 영향이 없을때), 이 옵션은 최상의 Throughput을 낼 수 있습니다. 해당 옵션을 gcpolicy의 기본 값입니다.

- optavgpause

Concurrent mark를 enable 시킵니다. GC로 인해 어플리케이션의 응답시간에 문제가 있다면, 응답시간을 줄이기 위해 사용할 수 있습니다. 그 대신 전체적인 Throughput이 감소할 수 있습니다.

- gencon 

GC로 인한 멈춤 시간을 최소화하는 것을  위해 Concurrent mark와 Generational Heap을 사용할 수 있습니다.

- subpool

Concurrent mark를 disable 시킵니다. Heap에 object를 할당할 때 더 성능을 향상하키기 위해 개선된 object 할당 알고리즘을 사용하는 것입니다. 이 옵션은 16Core 이상의 SMP 시스템상에서 사용해야 성능을 향상시킬 수 있습니다.


옵션을 선택하는 기준은 해당 시스템의 업무 특성에 따라 다를텐데요. 

예를 들어 GC로 인해 멈추는 현상이 특정 시간이 넘으면 절대 안되는 그런 시스템의 경우(공장MES 같이 일정한 응답이 이루어져야 하는 경우)는 optavgpause를 사용하여 전체적인 Throughput이 떨어지더라도 GC로 인한 응답시간은 보장받을 수 있습니다.


- Sweep 단계

Mark 단계에서 live object의 주소 저장소인 markbit vector와 모든 allocation object의 주소 저장소인 allocbit vector와 교차 비교하여 live object외의 garbage object를 삭제하는 작업을 수행합니다.

Parallel Bitwise Sweep 기능을 사용할 수 있으며, Parallel Mark와 같이 다수개의 Thread가 Sweep단계를 수행하기 위해 기동할 수 있습니다. 이러한 Parallel sweep을 위한 thread수는 -Xgcthreadn 옵션을 설정이 가능합니다.

또한 Makr 단계와 같이 Concurrent sweep을 사용할 수 있으며, GC Policy의 optavgpause 옵션을 설정하여 사용가능합니다.


- Compaction 단계

Sweep 단계에서 garbage object들이 삭제되고 나면, compaction 단계에서는 heap 상의 삭제된 garbage object들의 공간에 대해 재정렬 작업을 수행합니다. 

이러한 compaction 작업을 수행함으로써 연속된 free memory 공간을 확보할 수 있습니다.

compaction 작업은 object들이 heap memory상에서 이동이 발생하며 이 경우 모든 reference의 변경이 발생할 수 있어 수행 시간이 오래 걸립니다.

compaction 작업은 -Xnocompactgc 이 설정되어 있지 않고 다음과 같은 상황일 경우 발생할 수 있습니다.

- "-Xcompactgc"가 설정된 경우

- Sweep 단계 이후 object 할당을 위한 가용한 free space가 충분하지 않을 경우

- System.gc()가 -Xcompactexplicitgc가 설정되어 있을때 발생할 경우

- 적어도 이전에 가용한 메모리의 절반이 TLH allocation에 사용되었고, 평균 THL 크기가 1024byte 아래로 떨어질 경우

- 가용한 heap이  5%이하일 경우

- 가용한 heap이 128kb 이하일 경우


지금까지 One Heap 구조의 GC 동작 방식에 대해 알아 보았습니다. 

One Heap은 간단한 GC 알고리즘(Mark, Sweep, Compact)을 가지고 있으나, 그 내부에 각종 알고리즘과 옵션등으로 인해 복잡하게 느껴집니다. 

사실 알고보면 Sun 계열의 Minor GC에 비해 굉장히 간단한 구조입니다(저만의 생각일까요 ㅠ.ㅠ).


다음은 Generational Heap 구조의 GC 동작 방식에 대해 알아 보도록 하겠습니다.

위의 One Heap 구조의 GC에서도 설명드린 -Xgcpolicy:gencon으로 설정 가능한 Generational Heap 구조는 Sun 계열의 GC 방식과 유사하게 동작합니다.




위의 그림은 Generational Heap 구조에 대한 GC 처리 방식입니다.

scavenge 단계에서 Nursery 영역의 Allocate space와 Survivor space를 이용하여 GC를 수행합니다.

그 방식은 allocate space가 가득찰 경우 GC가 발생되며, allocate space의 garbage는 삭제되며, live object는 Survivor space로 복사됩니다. 

이러한 단계를 여러번 거치면서 live object는 Tenured space로 옮겨지게 됩니다.


Sun 계열의 Minor GC와 굉장히 유사하다는 것을 알 수 있습니다. 

그러나 Sun 계열의 옵션인 -XX:MaxTenuringThreshold 같은 옵션에 대한 내용은 기술 문서에서 찾을 수가 없었습니다(ㅠ.ㅠ).


이것으로 IBM 계열의 Java 메모리 구조, GC 동작 방식, GC 알고리즘 종류에 대한 설명을 마치도록 하겠습니다.
다음 시간에는 GC 로그 생성 및 분석 방법에 대해 설명드리도록 하겠습니다.
그럼 이만....



출처 -  http://blog.naver.com/bumsukoh?Redirect=Log&logNo=110119448575&from=postView 




Posted by linuxism
,

http://wiki.caucho.com/Java.lang.OutOfMemoryError:_PermGen_space 를 보면 컨텍스트를 리로딩 하도록 설정했을 경우에도 이런 현상이 나타날 수 있다고 하네요. 
실 운영 서버는 컨텍스트 리로드 기능을 무조건 꺼두셔야 합니다.(Tomcat 이 아니라 다른 WAS를 쓸 때도요. 보안상, 메모리 관리상 안좋습니다.) 


출처 -  http://www.okjsp.pe.kr/seq/71826 
============================================================================================

질문
eclipse에서 tomcat 5.5 플러그인에서 소스 수정시 자동 재시작이 가능한가요

Tomcat 이 활성화 되어 있는 상태에서 자바 파일을 수정 후 저장시

자동으로 Tomcat 이 재 시작되도록 환경설정을 바꿀 수 있는지 알고 싶습니다

매번 소스 수정시 (java, xml 등등) 변경 사항을 반영하기 위해서 서버를 재시작하는데

버리는 시간이 너무 많네요

답변

답변 드립니다. ^^

먼저 그런기능은 이클립스에서 설정하기 보다는

톰켓에서 설정이 가능합니다.

즉 톰켓이 로드하고 있는 class 에 변경이 일어나면

톰켓이 이를 감시하고 있다가 컨텍스트를 리로드 하게 됩니다.

방법은 아주 간단합니다. ^^

먼저 프로젝트를 만드셨고 그것을 톰켓에 돌리신다면

컨텍스트를 등록하셨을 거라고 생각됩니다.

컨텍스트는 보통 톰켓의 server.xml에 등록을 하거나

톰켓홈\conf\Catalina\localhost

폴더에 프로젝트명.xml

형태로 등록을 하셨을겁니다.

그럼 그 내용을 보면

<Context path="/Test" docBase="C:\workspace\Test" reloadable="true"/>

와 같은 형식의 내용이 있을겁니다.

바로 여기서 붉은색으로 되어있는

reloadable="true"  이부분이 추가가 되어있으면 소스를 변경하게 되면

알아서 리로드를 해주므로 서버를 재시작할 필요가 없습니다. ^^

이것은 계속감시하기위해 리소스를 많이 사용하므로 개발시에만 사용하도록 권해드립니다 ^^

그리고 그외에 web.xml 또는 server.xml과 같은

서버 설정 파일들은 변경을 하셨으면 수동으로 톰켓을 재시작을 해주셔야 합니다.  ^^

도움이 되셨길.. 



출처 - 네이버 지식

===========================================================================================





'Development > Java' 카테고리의 다른 글

자바 커뮤니티 프로세스(Java Community Process, 약자 JCP) & JSR  (0) 2012.02.07
GC Log 란 ?  (0) 2012.02.02
java - JVM 메모리 및 옵션  (0) 2012.02.02
Heap dump란?  (0) 2012.02.02
ClassLoader 문제 분석  (0) 2012.02.02
Posted by linuxism
,