2010년 8월 31일 화요일

JAVA(J2SE 1.4.1) 메모리 영역 구조

1. Sun Microsystyems의 자바 HotSpot VM은 힙을 세 개의 영역으로 나누고 있다.
 힙의 세 영역은 다음과 같다:
 1) Permanent space: JVM 클래스와 메소드 개체를 위해 쓰인다.
 2) Old object space: 만들어진지 좀 된 개체들을 위해 쓰인다.
 3) New(young) object space: 새로 생성된 개체들을 위해 쓰인다.
New object space는 세 부분으로 다시 나누어진. 모든 새로 생성된 개체들이 가는 Eden, 그리고 그 개체들이 나이들게(Old) 되기 전에 가는 Survivor space(From, To) 1과 2가 있다.


2. Garbage Collector
프로그램은 프로그램을 진행하면서 데이터들을 저장하는 것이 필요하다. 데이터들은 모두 메모리에 저장이 되는데, 저장할 데이터가 있으면 메모리의 일정 공간을 할당받아서 사용하게 된다. 프로그램 내에서 사용하게 되는 메모리를 'heap'이라고 한다. 더 이상 사용되지 않는 데이터에게 메모리를 계속 할당해 주는 것은 메모리를 낭비하는 것이므로, 그 데이터가 사용하던 메모리를 회수하는 것이 필요하다. 이러한 사용되지 않는 메모리에 대한 회수를 'Garbage Collection'이라고 한다. 자바에서는 프로그램이 사용하는 메모리를 JVM(Java Virtual Machine)이 모두 관리한다.


3. OutOfMemory Error 및 해결방법
자바는 객체, 변수등의 생성과 동시에 메모리(Heap)를 차지하게 되고, 문제는 이 객체와 변수를 너무 많이 발생시킴으로 해서 현재 할당된 메모리(Heap)를 초과하게 된다
그래서 더이상 할당받을 메모리(Heap)가 부족하게 되면 OutOfMemory Error 발생하게 된다.
OutOfMemory Error 해결방법으로는 jdk1.4에서 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC 옵션을 사용한  GC한 상태의 Heap메모리 정보출력 한다. GC정보를 통하여 New, Old, Perm 등의 영역중 실제 어느 부분이 부족하여 OutOfMemory가 발생하는지 찾은후 부족한 영역의 충분하 size를조절해 주는 방법으로 해결할 수 있다.


4. Heap layout 할당에 영향을 주는 스위치들

5. New Generation 메모리 할당 공식
   Eden = NewSize - ((NewSize/(SurvivorRatio + 2)) * 2)
   From space = (NewSize - Eden)/2
   To space = (NewSize - Eden)/2

6. Old Generation 메모리 할당 공식
   Old = Xmx - MaxNewSize

7.  JVM 스위치 설정 예제
 1) 현재 http://www.affis.net 서비스는 2200개의 Jsp파일을 가지고 있고 주로 정적이 페이지들이므로      Jsp 파일 로딩에 필요한 Perm size 위주로 메모리 튜닝을 하였다.
 2) 현재 http://club.affis.net 서비스는 어플리케이션 동적이페이지들로 작성되어 있고 어플리케이션        처리에 필요한  New size 위주로 메모리 튜닝을 하였다.

8. 맺음말
OutOfMemory 발생한다면 GC로그를 찍어본다. 로그를 분석해보면 New(eden, from, to), Old, Perm 등의 영역중에서 GC가 발생해도  메모리 영역이 계속 100%로 할당되는 영역이 보일것이다. 부족한 영역에 충분한 size 메모리를 할당해 주면 OutOfMemory 해결 된다.
그러나 부족한 영역에 계속해서 메모리 할당을 해주어도 사용률이 100%가 나온다면 프로그램 누수일수 있으니 프로그램을 점검해 봐야 할 것이다.

http://www.dude.co.kr
P 이경철님의 파란블로그에서 발행된 글입니다.

2010년 8월 4일 수요일

tomcat에 context 추가하기!!!

이젠 뭘 하나 하려면...  기억이 나질 않는다.... 된장.. ㅠ.ㅜ

$Tomcat\conf\Catalina\localhost 의 위치에 Default 로 설치된 admin.xml 파일을 복사하여
파일명을 원하는 컨텍스트명으로 변경한다.

 이미지를 클릭하시면 원본크기로 보실수 있습니다.




예제와 같이 http://localhost:8080/client/와 같은 컨텍스트명을 원하면 client.xml로 한다.


client.xml 파일의 내용은 다음과 같다.

----[ client.xml  ]----------------------------------
<Context
    docBase="E:\workspace\eclipse\tomcatClient"
    privileged="true"
    reloadable="true">
</Context>

reloadable = true 는 클래스 변경시 자동반영 옵션이다..
--------------------------------------------------

docBase 의 위치는 소스파일(물리적인 공간) 의 위치를 입력한다.

Context 추가 후 테스트를 위해 JSP 파일을 생성한다.
테스트를 위한 index.jsp 파일의 소스는 다음과 같다.


----[ index.jsp ]-----------------------------------

<%@ page contentType="text/html; charset=euc-kr" %>
<HTML>
<HEAD>
<TITLE> New Context Client </TITLE>
</HEAD>
<BODY>
Hello New Context ~~~  client  : 안녕
<%
 out.println("ContextPath : " + request.getContextPath());
%>
</BODY>
</HTML>

--------------------------------------------------

위의 내용을 실행한 결과는 다음과 같다.

이미지를 클릭하시면 원본크기로 보실수 있습니다.



Context 추가 완료~!!

http://www.dude.co.kr


P 이경철님의 파란블로그에서 발행된 글입니다.

Do you know tomcat monitoring tool is that Lam...

아~~따라~ 역쉬... 찾아 보면 다~~ 있어!!!!! 핫~ ㅋㅋ
일단 해당 사이트는 여기... http://www.lambdaprobe.org/d/installation.shtml


글구... 설정법... 적을려고 했는데...
이 것도 누군가가 잘~ 설명을 해두셨네...  캬~~~~~~~

------------------------------------------------------------------------------------

압축 푸신 후에 war파일을 webapps에 올려주시고
conf디렉토리 밑에 있는 tomcat-users.xml 수정해주세요.

 

<?xml version='1.0' encoding='utf-8'?>
    <tomcat-users>
          <role rolename="manager"/>
          <role rolename="admin"/>

          <role rolename="poweruser"/>
          <role rolename="probeuser"/>
          <role rolename="poweruserplus"/>
          <user username="admin" password="admin" roles="manager,admin,poweruser,poweruserplus,probeuser"/>

          <user username="tomcat" password="s3cret" roles="manager,admin"/>

    </tomcat-users>           

 
그리고
 내컴퓨터>속성>고급>환경변수>시스템 변수 에 다음을 추가해 줍니다.

    JAVA_OPTS
    -Dcom.sun.management.jmxremote



아마 Lambda Probe 사이트가 현재 안 열리고 있다.
그냥 이 파일 다운 로드 해서 사용하면 됩니다.^^

사용법은

probe.war를 $tomcat_home/webapps 에 올려놓고 tomcat을 시작하면 됩니다.
http://localhost:8080/probe/index.jsp


출처: http://www.voiceportal.co.kr/418

http://www.dude.co.kr




P 이경철님의 파란블로그에서 발행된 글입니다.

Junit 사용법

Junit Test case, suit 는 java application 을 위해 존재하는 것들이다.
Java application 이 아니고 web servlet 을 테스트 하고 싶을 때 Servlet Test Case 위자드를
사용하여 파일을 생성해서 테스트 해볼수 있다.이미지를 클릭하시면 원본크기로 보실수 있습니다.

보는 바와같이 상속받는 TestCase 클래스가 ServletTestCase 로 바뀌었다.
그리고 선택 옵션들이 많아졌다.
이미지를 클릭하시면 원본크기로 보실수 있습니다.

위자드로 자동 생성된 소스이다.

 public class JunitServletTest extends ServletTestCase {
       public JunitServletTest(String arg0) {
             super(arg0);
       }

       protected void setUp() throws Exception {
             super.setUp();
       }
       public void testMain(){
       }
       public void begin(WebRequest request) throws Exception {
       }
       public void end(WebRequest request) throws Exception {
       }
}
아래소스는 상속받은 ServletTestCase 클래스의 내용이다. Servlet 테스트를 하기위해 필요한
httpServletResponse 등과 같은 http관련 클래스 변수가 아래에 보일것이다.
public class ServletTestCase extends AbstractCactusTestCase
    implements CactusTestCase
{

    public ServletTestCase()
    {
    }

    public ServletTestCase(String theName)
    {
        super(theName);
    }

    public ServletTestCase(String theName, Test theTest)
    {
        super(theName, theTest);
    }

    protected ProtocolHandler createProtocolHandler()
    {
        return new HttpProtocolHandler(new DefaultServletConfiguration());
    }

    public HttpServletRequestWrapper request;
    public HttpServletResponse response;
    public HttpSession session;
    public ServletConfigWrapper config;
}
이와 관련된 로직을 이해하기 위해서는 Cactus 작동원리를 알아야한다.이미지를 클릭하시면 원본크기로 보실수 있습니다.

그림을 설명하자면 먼저 브라우저에서 URL TestCase 를 호출하게 되면
Junit Test Runner YYYTestCase runTest() 메서드를 호출하게 된다.
그 메서드는 begin(), beginXXX() 차례로 수행하면서 beginXXX 에 전달된
WebRequest 매개변수를 이용해서 HTTP 관련변수를 셋팅한다.
다음은 Redirector Proxy HTTP 연결을 확립하여 설정된 헤더 및 매개변수를 전달한다.

Redirector Proxy 는 이름 그대로 대리자 역할을 하는데 Client 에 생성했던것과 같은
Junit Test Runner 을 서버측에서 다시 한번 인스턴스를 생성한다. 서버측은 클라이언트와 달리
setUp, testXXX, tearDown 으로 실행된다.
testXXX 메서드는 Junit assert API 를 사용하여 테스트를 수행하고 서버측  서블릿코드를
호출하게 된다. 그리고 서버객체에 대한 레퍼(Wrappers) HTTP세션을 생성한다.

Exception 이 발생하게 되면 Redirector Proxy 에 의해 검출되며 클라이언트 측에 전달하여
Junit 에 의해 화면에 출력된다.

정상수행일 경우 YYYTestCase.runTest() 메소드는 endXXX, end 를 차례대로 호출한다.

서블릿 테스트 코드를 만들면 다음과 같이 간단하게 만들었다.
호출할 Servlet 서버소스 이다.
public class LoginServlet extends HttpServlet {
       public void doGet(HttpServletRequest req, HttpServletResponse res)
                   throws ServletException, IOException{
             PrintWriter out = res.getWriter();
             HttpSession session = req.getSession();
             String id = req.getParameter("id");
             String passwd = req.getParameter("passwd");
             if (checkLogin(id, passwd)){
                    session.setAttribute("id", id);
                    out.print(id+"Login Failed");
             }else{
                    out.print(id+"Login Success");
             }
       }
       private boolean checkLogin(String id, String passwd){
             return true;
       }
}

다음은 TestCase 클래스이다.
import javax.servlet.ServletException;
import org.apache.cactus.ServletTestCase;
import org.apache.cactus.WebRequest;

import com.meterware.httpunit.WebResponse;

public class JunitServletTest extends ServletTestCase {

       public JunitServletTest(String arg0) {
             super(arg0);
       }

       protected void setUp() throws Exception {
             super.setUp();
       }
       public void testMain(){
             LoginServlet servlet = new LoginServlet();
             try {
                    servlet.init(config);
                    servlet.doGet(request, response);
             } catch (ServletException e) {
                    e.printStackTrace();
             } catch (IOException e) {
                    e.printStackTrace();
             }
             assertEquals("bcho", session.getAttribute("id"));
       }
       public void begin(WebRequest request) throws Exception {
       }
       public void beginLogin(WebRequest request) throws Exception {
             request.addParameter("id", "bcho");
             request.addParameter("passwd", "passwd");
       }
       public void endLogin(WebResponse response) throws Exception {
             String responseTxt = response.getText();
             assertTrue(responseTxt.indexOf("success") > 0);
       }
       public void end(WebResponse response) throws Exception {
       }
}


http://www.dude.co.kr





P 이경철님의 파란블로그에서 발행된 글입니다.