웹 어플리케이션들은 보통 아래의 구조를 가지고 있습니다.
-lib
-classes
그리고, 각 어플리케이션마다 별도의 클래스 로더가 클래스들을 로딩합니다..
그런데.. 위의 lib 폴더는 클래스 패스로 안 잡네요.. ^^;;
어쩐지, 각종 프레임웍들의 설정파일들이 classes 폴더에 넣는 이유가 있었네요.. ^^;;
웹 어플리케이션들은 보통 아래의 구조를 가지고 있습니다.
그리고, 각 어플리케이션마다 별도의 클래스 로더가 클래스들을 로딩합니다..
그런데.. 위의 lib 폴더는 클래스 패스로 안 잡네요.. ^^;;
어쩐지, 각종 프레임웍들의 설정파일들이 classes 폴더에 넣는 이유가 있었네요.. ^^;;
이것도 문서를 정리하다가 발견했네요. ^^
1. 톰캣 메모리 릭 : http://java.dzone.com/articles/memory-leak-protection-tomcat
웹 어플리케이션을 로딩할때, 클래스 로더가 각 어플리케이션별로 세팅이 되고, 이 로더가 클래스를 다시 로딩하면서 기존의 클래스들에 대한 reference를 클래스 로더가 유지를 하고 있어서 eden 영역의 메모리가 차는 현상이 발견. 결과로 OutOfMemory Error
2. 패치 : 7.0대 버전에서 발견되서, 6.0.24 버전(http://mirror.khlug.org/apache/tomcat/tomcat-6/v6.0.24/RELEASE-NOTES)에 반영
며칠전에 사석에서 상사분이 톰캣(Tomcat)은 IIS에 비해서 connection을 적게 받고, 그로 인해서 성능이 떨어진다고 말씀을 하시네요. ^^;; 서비스의 전체적인 성능 문제를 자바(Java)나 톰캣이 문제가 있다는 시각이어서, 자바쪽의 경험치로 말씀하시는게 아니라 선입견(Overlapped I/O의 성능만 말씀하시네 ^^;;)으로 얘기를 하고 있다는 느낌이 많이 받았습니다. 대체로, 서비스의 성능 이슈는 톰캣이나 IIS보다 그 위에 올라가는 애플리케이션이 더 성능에 영향을 미칠텐데 말입니다. ^^;;
그래서 IIS 기반의 ASP.NET 서비스들이 주로 사용하는 DataSet에 대해서 Serialize 데이타에 대해서 살펴보았다. 비교는 단순히 자바, C# Object, C# DataSet으로 10개의 리스트를 가지는 모델을 가지고 했다. 아래의 코드로 자바에서의 Object Array, C#에서의 Object Array, C#에서의 DataSet의 Serialize된 객체의 사이즈를 알 수 있다. 단순하게 Serialize하는 속도 및 Deserialize하는 속도는 같다고 가정을 한다.
* Java
– SerializeModel.java
import java.util.ArrayList; import java.io.Serializable; public class SerializeModel implements Serializable { private static final long serialVersionUID = -7168303693593724718L; private int count = 0; private String name = null; private String address = null; private ArrayList<SerializeModel> models = new ArrayList<SerializeModel>(); public SerializeModel(int count, String name, String address) { this.count = count; this.name = name; this.address = address; } public void addModel(SerializeModel model) { this.models.add(model); } }
– SerializeTest.java
import java.io.FileOutputStream; import java.io.ObjectOutputStream; public class SerializeTest { public static void main(String[] args) throws Exception { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("java.ser")); SerializeModel model = new SerializeModel(0, "a", "b"); for(int i=0; i<10; i++) { model.addModel(new SerializeModel(i, i +" name", i +" address")); } out.writeObject(model); out.flush(); out.close(); } }
* C#
– SerializeModel.cs
using System; using System.IO; using System.Runtime.Serialization; using System.Collections; using System.Collections.Generic; namespace SerialzieTest { [Serializable()] class SerializeModel { private int count = 0; private String name = null; private String address = null; private ArrayList models = new ArrayList(); public SerializeModel(int count, String name, String address) { this.count = count; this.name = name; this.address = address; } public void AddModel(SerializeModel model) { this.models.Add(model); } } }
– SerializeModelDataSet.cs
using System; using System.Data; using System.Collections.Generic; using System.Text; namespace SerialzieTest { [Serializable] class SerializeModelDataSet { private DataSet dataSet = new DataSet(); public void AddDataTable(DataTable table) { this.dataSet.Tables.Add(table); } public DataSet GetDataSet() { return this.dataSet; } } }
– Program.cs
using System; using System.Data; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; namespace SerialzieTest { class Program { static void SerializeObjectArray() { Stream stream = File.Open("csharp.ser", FileMode.Create); BinaryFormatter bformat = new BinaryFormatter(); SerializeModel model = new SerializeModel(0, "a", "b"); for (int i = 0; i < 10; i++) { model.AddModel(new SerializeModel(i, i + " name", i + " address")); } bformat.Serialize(stream, model); stream.Flush(); stream.Close(); } static void SerializeDataSet() { Stream stream = File.Open("csharp_dataset.ser", FileMode.Create); BinaryFormatter bformat = new BinaryFormatter(); SerializeModelDataSet model = new SerializeModelDataSet(); DataTable table = new DataTable(); DataColumn itemCount = new DataColumn("count", Type.GetType("System.Int32")); DataColumn itemName = new DataColumn("name", Type.GetType("System.String")); DataColumn itemAddress = new DataColumn("address", Type.GetType("System.String")); table.Columns.Add(itemCount);</span> table.Columns.Add(itemName); table.Columns.Add(itemAddress); DataRow row; for (int i = 0; i < 10; i++) { row = table.NewRow(); row["count"] = i; row["name"] = i + " name"; row["address"] = i + " address"; table.Rows.Add(row); } model.AddDataTable(table); bformat.Serialize(stream, model); stream.Flush(); stream.Close(); } static void Main(string[] args) { SerializeObjectArray(); SerializeDataSet(); } } }
위 코드를 사용해서 저장한 Object의 사이즈는 아래와 같습니다.
네트웍으로 전송되는 데이터의 크기는 성능에 중요한 영향을 준다는 것은 이미 알고 있다. 성능을 높이기 위해서 Socket Buffer의 사이즈를 적당히 줄이는 것도 팁중의 하나이다. 그리고, 위 코드로 만들어지는 C#의 DataSet은 더욱 멋진 모습을 보여준다. 아래의 화면처럼 말이죠.. 아래의 화면은 Hex Viewer로 본 화면이다.
Object의 Serialize는 C#이 version, locale 및 가비지(?) 데이타로 인해서 좀 더 크게 나온다. 그리고, 중간의 DataSet은 Serialize된 내용을 보면, xml의 형태로 데이터를 저장하고 있다. 결국 DataSet을 데이타로 직렬화해서 네트웍으로 전송하게 되면, 데이터 크기보다는 Serialize/Deserialize할때의 String연산(XML 데이타 리드)이 성능저하의 주범이 될 것 같다. 결국, Tomcat, IIS가 중요한게 아니라 C#에서 널리 쓰이는 DataSet을 많이 사용하고 있는 IIS기반의 ASP.NET 어플들의 서비스가 더 문제가 아닐까 생각한다.
1. 어플리케이션 서버에서 필요한 메모리 계산 방법
– 계산식 : (MaxProcessMemory – JVMMemory – ReservedOsMemory) / (ThreadStackSize) = Number of threads
– 메모리 계산 예
가정 : Java 1.5를 사용중이며 OS가 120MB를, 디폴트 스택사이즈는 0.5M
2. Application Server 에러 대처 방안(java.lang.OutOfMemoryError: PermGen space 현상)
3. Tomcat에서 설정 예시
위 설정을 통해 출력되는 로그를 보고 New Generation의 eden 영역, Old Generation 영역, Permanent 영역을 확인하여 각 영역이 작으면 아래와 같은 설정으로 적당 사이즈를 확보해 줍니다.
결론적으로 적용할 설정은 아래와 같습니다.
Open Soure는 100% 안정적이지 않기 때문에 가장 최신의 안정적인 버젼이 릴리즈되는지 항상 예의 주시하여 버전업에 게을러서는 안됩니다
위 내용은 http://www.mimul.com/pebble/default/2008/01/26/1201346400000.html 에서 발췌를 하였습니다.
Tomcat5.5 클래스 로딩 순서
Bootstrap classes of your JVM
System class loader classses (described above)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
$CATALINA_HOME/common/classes
$CATALINA_HOME/common/endorsed/*.jar
$CATALINA_HOME/common/i18n/*.jar
$CATALINA_HOME/common/lib/*.jar
$CATALINA_BASE/shared/classes
$CATALINA_BASE/shared/lib/*.jar
Tomcat5.0 클래스로딩 순서
Bootstrap classes of your JVM
System class loader classses (described above)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
$CATALINA_HOME/common/classes
$CATALINA_HOME/common/endorsed/*.jar
$CATALINA_HOME/common/lib/*.jar
$CATALINA_BASE/shared/classes
$CATALINA_BASE/shared/lib/*.jar
Tomcat4.1 클래스로딩 순서
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
Bootstrap classes of your JVM
System class loader classses (described above)
$CATALINA_HOME/common/classes
$CATALINA_HOME/common/endorsed/*.jar
$CATALINA_HOME/common/lib/*.jar
$CATALINA_BASE/shared/classes
$CATALINA_BASE/shared/lib/*.jar
* Reference
– http://www.jakartaproject.com/article/jsptip/111456818395700