'Technical Note'에 해당되는 글 134건

Technical Note/JAVA

Q : 특정 쿼리가 PreparedStatement로 실행하면 너무 느린데 같은 쿼리를 Statement 로 실행시는 1초도 안걸립니다. 이유는?



A1 : 첫번째 생각할 것은 최적화기의 문제입니다. 오라클의 경우엔 규칙기반 최적화와, 비용기반 최적화기가 있는데 각각을 rule-based optimizer와 cost-based optimzer가 있습니다. 그리고 이런 최적화기를 선택하는 기준을 설정하기 위한 파라미터로 optimizer_goal 인가하는 파라미터가 있는데 이 값이 all_rows인 경우 쿼리를 olap성으로 파악해서 throughput을 최대화하고, first_rows인 경우에는 oltp성으로 파악해서 response time을 최소화 합니다. 둘다 maximize되는 모드는 없습니다. 예를 드는게, 테이블을 읽을 때 어떻게 읽을까 하는 전략인데 all_rows의 경우에는 full table scan을 지향하고, first_rows에서는 index scan을 사용합니다. 룰 기반 최적화기는 이와 달리, 각종 스캔방식에 점수를 미리 매겨놓고 이 점수대로 최적화하는 것입니다. 가령, 어떤 행을 인덱스로 읽는게 10점이면 풀 테이블 스캔은 5점 이런식입니다. 따라서 인덱스가 있다면 인덱스를 무조건 씁니다. (점수가 높으니까요.) 하지만 인덱스라는게 반환하는 행의 개수가 전체 10~15%일때 인덱스 사용의 효과가 나타나는게 일반적인데, 이 것까지는 룰 기반 최적화에서는 고려하지 않습니다. 다시 말해 옛날 방식이란 거죠. 별다른 설정을 하지 않았다면 아마도 최적화 모드가 all_rows일 텐데 반응시간을 높이고 싶다면 이것을 first_rows로 바꿔주어야합니다. 바꾸는 방법은 oracle 8i 이하에서는 init{SID}.ora (여기서 {SID}자리에는 실제 SID를 적어주면 됩니다. 예를들어 ORCL이라면 initORCL.ora가 됩니다)를 열어서 수정하고 데이터베이스를 재시작하면 됩니다. 오라클 9이상부터는 이렇게만 하면 안되고 방식이 조금 바뀌었는데, 자세한건 저도 기억이 안나네요.. 메뉴얼이나 otn에 물어보세요. (otn.oracle.co.kr 가셔서 좌측에 포럼 클릭하시면 됩니다.)
두번째 생각할 것은, prepared statement는 실행계획을 한번 만들고 계속 재사용한다는 것입니다. 따라서 값의 분포등이 바뀌었어도 이런걸 고려 안해주고 예전에 만든 실행계획을 계속 사용합니다. 따라서 새로이 인덱스를 만들었거나 해도 무조건 예전의 실행계획만 쓰게 되죠. 그래서 이걸 제대로 반영하려면 매번 실행 계획을 작성하는 statement를 쓰시거나 아니면 shared pool이라는 오라클내 공유메모리를 비워주면 되는데 alter system flush shared_pool; 이란 명령을 씁니다. ('_'를 빼야하는건지도 모르겠네요. 잘 기억이 안나서.. 죄송.) 

세번째 생각할 내용은, 실행 계획이 매번 잘 바뀌도록 비용을 제대로 산정해주고 있는가의 문제인데, 비용 산정을 위해서는 값의 분포(히스토그램)나 전체 행의 수같은 정보가 필요합니다. 이것을 분석하는 명령은 자체 제공하는 dbms_stats 패키지가 있고, analyze명령이 있고, monitoring 옵션이 있습니다. 제대로 해주려면 이런 비용 측정 정책도 잘 정립해야됩니다. 자세한 내용은 굉장히 많으니 서적이나 asktom.oracle.com에서 검색을 통해서 참고하시기 바랍니다. 마지막으로 말씀드리고 싶은건, 자주 실행하는 명령도 아니고 그러면 그 문장 하나 Statement로 한다고 해서 큰일날 일도 없단 것입니다. 몽땅 다 Statement로 코딩했다면 모르되, 한두개 쿼리가 Statement라고 심각한 성능저하가 생기고 하지는 않습니다. 

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

A2 : BIND 를 쓸 경우 실행계획이 틀어져서 느려지는 그런 경우를 unsafe literal 이라고 합니다. 예를 들어...

select * from emp where empno = :v1

위의 SQL에서 empno 는 emp의 PK입니다. 따라서 preparedStatement를 써서 BIND변수를 사용하든지 그렇지 않든지 실행계획은 똑 같이 나옵니다.

이런 경우를 safe literal 이라고 합니다. 하지만,

select * from emp where deptno > :v1

위의 경우... :v1이 ...  1 일 경우와 1000일 경우는 분포도가 전혀 다릅니다. 1일 경우에는 
대부분의 deptno가 1보다는 크기 때문에... 분포도가 넓습니다. 즉, 인덱스를 타지 않는게
더 좋습니다.    하지만 deptno가 1000보다 큰 경우는 거의 없습니다. 즉, 분포도가 좁습니다. 이 경우 인덱스를 타야 합니다.

그러니가 히스토그램이라는 것은 이처럼 실재 :v1 값이 무엇이냐에 따라서 분포도가 달라지는 분포도 정보입니다. 어느 value가 어느 정도의 분포도를 가지고 있는지 그 정보를
히스토그램이라고 합니다.

문제는 BIND를 쓰면... :v1 이 1이 들어올지 1000이 들어올지에 무관하게 무조건 단 하나의 실행계획만을 만들고 일괄적으로 적용하다가 보니...  1000이 들어오는데도 불구하고 인덱스를 타지 않고 Full Scan하는 상황이 나올 수 있습니다.

즉, BIND 변수를 활용하며... 히스토그램 정보를 활용할 수 없습니다.

그렇다고면? prepatedStatement를 쓰지 말아야 할까요???  아닙니다. 써야 합니다.
위와 같이 불충분한 통계정보(히스토그램)이 없어서 실행계획을 잘못 수립해서 느려지는 경우는 어쩔 수 없는 현재의 옵티마이져의 한계로 보아야 합니다. 이 경우 똑똑한 사람이
힌트 등을 통해서 SQL에게 올바른 실행계획을 가르쳐줘야 합니다.

아주 특수한 경우 위의 이유로 튜닝을 위해 Statement를 쓰는 경우도 있습니다.
예를 들어... 성별이 남, 여 두가지일 경우... 남자가 전체의 2%이며 아주 극소수라고 가정하면.. 남자일 경우에는 인덱스르 타야하고... 여자일 경우 인덱스를 타지 말아야 합니다.
이 경우... 어차피 distinct 값의 종류가 딱 2가지 이므로... BIND를 쓰지 않아서
하드파싱을 해봤자... 2개의 SQL 종류 밖에는 나오지 않으므로 문제가 없습니다.

select * from user where sex = 'm'
select * from user where sex = 'f'

오라클의 Shared pool의 Library cache에는 위와 같이 딱 두종류의 SQL이 저장되어있어서 재사용되겠지요. 답변이 길었는데... 위의 이야기는 DBMS에 대해서 잘 아시는 분이 아니라면 어려울 수도 있습니다.

간단하게 이야기해서 실행계획을 비교해보십시오.

BIND변수를 썼을 때와 그렇지 않았을 때를... 분명이 위의 경우 실행계획이 전혀 다르게 나올겁니다. 그러니까. Unsafe literal 이죠.

따라서 ... BIND 쓰지 않았을 경우와 똑같이 실행계획이 나오도록 힌트를 사용해서 조정해 주십시오.

반드시 preparedStatement를 쓰시구요. 어쩌다 일주일에 한번쯤 돌리는 SQL이 아니라... 수시로 똑 같은 SQL이 반복적으로 계속 들어온다면 반드시 preparedStatement로 작성하셔야합니다. 즉, OLTP에서는 무조건 써야 합니다.


Technical Note/JAVA

Tomcat GC 에 대한 튜닝 방법
  1. 4cpu 일때 young, old 영역에 대해서 GC가 이루어지고 old 영역이 70일때 Full GC가 일어남
  2. tomcat/bin의 catalina.sh에 추가
    Tomcat GC 옵션

    JAVA_OPTS="-server -Xms1024m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=128m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -Djava.awt.headless=true -Dcom.sun.management.jmxremote"

    option 중 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps는 10분 마다 GC 상태를 찍을 경우 필요함(기본은 필요 없음)


JVM Memory구성 옵션
  1. 메모리는 최대 Physical Memory의 1/2정도 설정시까지 문제 없음
    JVM Memory구성 옵션

    -Xms<Size> : 초기의 전체 힙 메모리의 크기 설정
    -Xmx<Size> : 최대 전체 힙 메모리의 크기 설정
    -XX:NewSize=<Size> : Young 영역의 메모리 크기 설정
    -XX:MaxNewSize=<Size> : 최대 Young영역 메모리 크기 결정
    -XX:NewRatio=<n>: Young영역의 메모리 크기를 결정하는 또 다른 방식 전체 메모리 크기에서 1/(n+1)만큼 Young영역 메모리로 할당된다.


먼저 알아둬야할 지식 Java HotSpot VM이 세가지 영역으로 힙을 분할해서 사용한다는 것. 이것을 기반으로 GC 정책을 세운다.
  1. Permanent space (반 영구적인 영역 ) : JVM 클래스와 method 객체가 사용한다
  2. Old object space (오래된 객체의 공간) : 잠시동안 있는 객체가 사용한다.
  3. New (young) object space (새로운 객체 공간 ) : 새로 생성한 객체가 사용한다.
    JVM 옵션

    -XX:+UseSerialGC: Young영역에 대한 GC. Young영역에서 살아남은 객체를 Old영역으로 복사하는 방식으로 동작. GC Thread가 1개임. Stop-the-world방식임. 이 옵션은 Java SE 5 이후 버전만 사용 가능.

    -XX:+UseParallelGC: Young영역에 대한 GC. GC Thread가 여러개 동작하지만, Stop-the-world방식. 즉 Application Thread를 멈추고, 여러 Thread가 GC를 수행함. Young영역이 100%사용하게 되었을때 동작한다. -XX:ParallelGCThreads 과 함께 사용 가능.

    -XX:+UseParNewGC : CPU가 여러개 있는 서버의경우에 유용

    -XX:+UseTLAB : Thread가 많고 객체 생성이 빈번한 경우, 공유메모리를 사용하는 것 보다는 스레드별로 메모리를 할당하는 것이 좋다 .16개 이상의 CPU를 장착한 시스템의 경우 쓰레드별로 객체 생성을 하기 이한 옵션

    -XX:+UseConcMarkSweepGC : Stop the world의 시간을 줄이기 이해서 작업스레드와 병행하여 GC정보를 수집한다.(Mark-sweep방식) -XX:ParallelGCThreads와 함께 사용하는게 좋을듯. CPU가 두개 이상이라면 사용하는게 좋을듯 하다.

    -XX:ParallelGCThreads=<n>: 병렬 가비지 컬렉터에서 가비지 컬렉션 스레드 수를 지정. 기본값은 CPU수와 동일하다.


Technical Note/JAVA
옵션의 종류
  • -X로 시작하는 옵션 : 비표준. JDK의 버전에 따라, 예고없이 변경될 수 있다.
  • -XX로 시작하는 옵션 : 안정화되지 않음(not stable). 일반적인 사용에 권장되지 않음. 이 옵션 또한 예고없이 변경될 수 있다.
    • Boolean옵션은 -XX:+<option> 으로 켜고, -XX:-<option>으로 끈다.
    • Numeric(숫자)옵션은 -XX:<option>=<number>로 설정한다. 사용되는 숫자에 m | M (mega), k | K (kilo), g | G (giga)를 포함할 수 있다.
    • String(문자)옵션은 -XX:<option>=<string>으로 설정한다. 보통 file, path, command list를 명시하기 위해 사용한다.
      optionsdescription
      -verbose:gcGC이벤트가 발생할때 마다 메시지를 reporting한다.
      -XmsN초기 memory allocation pool의 초기사이즈
      -XmxNmemory allocation pool의 최대 사이즈
      -XssNThread stack의 사이즈를 설정
      -XX:NewSize=2.125mnew generation영역의 기본크기
      -XX:MaxNewSize=sizeNew Generation(Eden + S0 + S1) 의 최대 크기를 설정한다.
      -XX:PermSizePermanent Generation의 기본사이즈
      -XX:MaxPermSize=64mPermanent Generation의 최대사이즈
      -XX:NewRatio=2old/new generation영역 크기의 비율
      -XX:SurvivorRatio=8eden/survivor영역 크기의 비율
      -XX:ThreadStackSize=512Thread Stack의 크기
      -XX:-PrintGCGC가 일어날때 message를 출력한다.
      -XX:-PrintGCDetailsGC에 관해 더 자세한 메시지를 출력한다.
      -XX:-PrintGCTimeStampsGC의 timestamp를 출력한다.
JVM Tuning Example

JAVA_OPTS=-Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:SurvivorRatio=4 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

HeapSize1024M
New Generation512M
Eden348M
Survivor187M
Survivor287M
Old Generation256M
Permanent256M


Technical Note/SERVER PERFORMANCE

JVM Memory 운용 모델

 

1. System Memory Model
java Test이 발생하고나서의 상황
---------------------------------------------
- 구획별 메모리는 64KB단위로 구분되어 있습니다.

┌────────────┐CS: Code Segment
│[코드 영역]                    │ 
│Test Class의 Source가    │ 
│등록되는 영역                 │ 
├────────────┤DS: Data Segment
│[Data 영역]                    │
│static변수,                     │
│static 메소드 저장           │
│main()                           │ 
│객체를 만들지 않아도       │
│이영역의 요소 사용가능    │
├────────────┤SS: Stack Segment
│[Stack 영역]                  │
│메소드가 사용하는 영역    │
│메소드 안에서 선언되는    │ 
│지역변수가 선언,             │
│메소드 처리가 끝나면       │ 
│메모리가 자동으로           │ 
│회수됨                           │ 
├────────────┤
│[Heap 영역]                   │
│객체가 생성되면              │
│존재하는 영역,                │
│RAM의 양에 따라 무한대  │
│GC의 대상이 되는 영역    │
└────────────┘

 

 

 

2. JVM Memory Model

Code Area ----- Data  ---- Stack --------------------- Index Table ----- Heap
                        Area                                                   Hash Table
----------------------------------------------------------------------------------------
Source              Static        메소드가 사용하는 영역          레퍼런스 값          주소
                        변수
                        메소드
----------------------------------------------------------------------------------------
메소드(공유)                      객체 변수1                            this, super       멤버변수  
int k=0;                              지역 변수                                                  인스턴스 변수
int m = 0;                           객체 변수2
int tot = 0;                          Test obj = new Test()  ---->  1000 0xFF00      0xFF00 int k...
int Total(){}                       Test obj2 = new Test()  --->  1001 0xFF08      0xFF08 int k...
                                       obj2 = obj;

                                

                                       Test obj3 = new Test()
                                       obj.tot = obj.Total(); 
                                       obj3.tot = obj3.Total();          

 


▩ static 변수(정적 변수, 클래스 변수), static method(클래스 메소드)
   - 자바 JVM으로 소스가 적재될시에 자동으로 Data Area에 메모리 할당을 받습니다.


   - new를 이용해 객체를 만들지 않고 사용 가능합니다.


   - 색상 정보등 단순한 값을 참조할 경우와 값을 편집하는 경우에 사용합니다.


   - static 변수는 객체 생성시에 오로지 하나만 생성됩니다.


   - static 변수는 객체 생성시에 오로지 하나만 생성됨으로 클래스 변수라고 합니다.


   - static변수는 DS(Data Segment) 데이터 영역을 사용합니다.

 

1. Hash Code의 출력
   - 객체의 Hash Code는 SUN에서 지정한 JVM의 해시알고리즘에 의해 해시코드가 산출됩니다.

   - String은 객체변수의 값이 같을 경우 즉 같은 문자열을 가지고 있으면 Hash code를 공유합니다.


     String str1 = "왕눈이";
     String str2 = "왕눈이";
     
     str1.hashCode() = str2.hashCode();


>>>>> HashCodeTestMain.java
class HashCodeTest {
    //멤버 변수, instance 변수, heap, 객체 사이트 8바이트
    int kuk=100;
    int eng=100;
}

public class HashCodeTestMain {
    //Data Area
    public static void main(String[] args) {
        //Stack: hct1       Heap
        //객체 변수: Hash Code값을 가지고 있습니다.
        HashCodeTest hct1 = new HashCodeTest();

        System.out.println("hct1.hashcode:" + hct1.hashCode());
    }
}

 


출력 결과
---------
hct1.hashcode:7699183

 


2. static 변수는 객체를 만들지 않아도 접근할 수 있습니다.

>>>>> Scjp.java
class ScjpPass{
    //멤버 변수, Heap
    int t1=0;
    int t2=0;
    int t3=0;
    int t4=0;
    
    //클래스 변수, Data area
    static int BONUS=100; 
    
    //생성자, Source area
    public ScjpPass(){
    }
    
    //생성자, this = sp객체가 가지고 있는 hash code
    //sp객체의 heap메모리를 공유하게됩니다.
    //int t1, int t2, int t3, int t4: Stack
    public ScjpPass(int t1, int t2, int t3, int t4){
        //Heap = Stack
        this.t1 = t1;
        this.t2 = t2;
        this.t3 = t3;
        this.t4 = t4;        
    }
    
}


public class Scjp {
    public static void main(String[] args) {
        System.out.println("ScjpPass.BONUS: " + ScjpPass.BONUS);  
        
        //t1은 static이 아님으로 클래스명으로 접근 할 수 없습니다.
        //System.out.println(ScjpPass.t1);
        //heap memory 할당
        ScjpPass sp = new ScjpPass(85, 90, 80, 70);
        System.out.println("sp.t1: " + sp.t1);
        //static변수는 클래스명으로 접근을 권장합니다.
        //System.out.println("sp.BONUS: " + sp.BONUS);
    }
}

 


3. static 메소드는 객체를 만들지 않고도 호출할 수 있습니다.
   - wrapper 클래스에서 많이 사용되며 단순 기능만을 사용할 경우 구현합니다.

 

>>>>> SCWCDmain.java
//하나의 java 파일안에 클래스가 2개이상 존재하는 경우
//main()메소드가 있는 오직 하나의 클래스만 public을 선업합니다.
//일반적으로 main()가 있으면 무조건 public을 선언하며
//파일명은 public 클래스명과 일치해야 합니다.

class SCWCD{
    int t1=0;
    int t2=0;
    int t3=0;
    int t4=0;
    static int BONUS=100; 
        
    public SCWCD(){
    }
    
    public SCWCD(int t1, int t2, int t3, int t4){
        this.t1 = t1;
        this.t2 = t2;
        this.t3 = t3;
        this.t4 = t4;        
    }
    
    public String pass(){
        String msg=null;
        if (t1 >= 65 && t2 >=65 && t3 >=65 && t4>=65){
            msg="축하합니다. 합격입니다.";
        }else{
            msg="축하합니다. 불합격입니다.";
        }
        return msg;
    }

    //클래스 메소드 
    public static void prLine(){
        System.out.println("****************");
        System.out.println("   ITWILL       ");
        System.out.println("         JAVA   ");
        System.out.println("****************");
    }
}

 

public class SCWCDmain {
    public static void main(String[] args) {
        //객체를 만들지 않고도 호출가능합니다.
        SCWCD sc = new SCWCD();
        //객체명.멤버변수, 멤버 메소드
        sc.t1 = 100;
        //sc.prLine();
        
        //클래스.static 메소드명
        SCWCD.prLine(); 
    }
}

 


4. 객체를 생성하면 멤버변수는 전부 기본값이나 생성자에서 지정한 값으로 초기화됩니다. 
   하지만 static변수는 프로그램을 실행시 최초 한번만 특정값으로 초기화되고

   (여기서는 0으로 초기화) 더 이상 초기화가 되지않습니다. 
   따라서 한번 만들어진 static변수는 계속적으로 값이 증가 및 감소됩니다.
   - static 변수는 객체를 여러번 생성해도 한번만 생성이 됩니다.
   - static 변수는 멤버 메소드에 선언할 수 없습니다.

 

>>>>> StaticDemo.java
class Box {
  //인스턴스 변수, 전역변수(객체를 생성시마다 초기화됩니다.)   
  int         cnt   = 0;
  
  //단 1회만 초기화 됩니다. 소스 로딩시에 메모리를 
  //한번만 할당 받습니다.
  static long boxID = 0;
  
  public Box() {
    long count=0;  
    boxID = boxID + 1; //static variable
    cnt = cnt + 1;    //member variable
    System.out.println("cnt: " + cnt);
    System.out.println("BoxID: "+ boxID );
    
  }
  
  //멤버 메소드에서는 static변수를 선언할수 없습니다.
  /*
  public void staticTest(){
      static long count=0;
      count=count+1;
      
  }
  */
  
  //static(class) 메소드에 static 변수를 선언할 수 없습니다.
  /*
  public static void staticTest2(){
      static long count=0;
      count=count+1;
      
  }
  */
  
}
  
public class StaticDemo {
    public static void main(String args[]) {
        //객체 생성  
        Box mybox1 = new Box();
        Box mybox2 = new Box();
        Box mybox3 = new Box();
    }
}

 

 


▩ 값을 변경할 수 없는 final 변수(상수 선언)
   - 값을 변경할 수가 없습니다.

   - 값을 고정할 필요가 있는 코드와 같은 형태의 데이터에 사용합니다.
      예)1년 12달, 요일, 주7일


>>>>> Finalmain.java
class Final{
    int money=10000;
    final int day=7;    //1주
    final int week = 4; //한달
    
    //상수 선언
    final static int month=12; //1년
    
    //생성자가 존재 하지만 아무런 처리를 하지 않습니다.
    public Final(){}     
}

public class Finalmain {

    public static void main(String[] args) {
        Final fi = new Final();
        fi.money = 15000;
        //final변수는 값을 변경(대입)할 수 없습니다. 
        //fi.day = 10;
        System.out.println("1주일 용돈:" + fi.money * fi.day);
        System.out.println("1년" + Final.month + "달");
        //Final.month = 20000;
    }
}

Technical Note/SERVER PERFORMANCE
http://blog.daum.net/kr_girls/8451047
Application Debugging을 하다 보면간간히 들어오는 Issue OOM(Out Of Memory)에 대한 이슈인데이거 생각보다 골치가 아프다사실 이를 위해서 DebugDiag  UMDH 라는 훌륭한 Tool에 의지하며, Allocation pattern을 Check 하는 것은 debugging도 아니지만눈에 띄는Allocation pattern이나 메모리상에 보유하는 있는 실제 Allocation(Committed) region이 그다지 높지 않은 데도 불구하고 OOM현상이 발생할 수 있다는 데에 어이없어 질 때가 있다그러면서 Application 개발자는 분명히 Allocation/release 를 엄격하게 지켰을 뿐인데... 라고 말하기도 한다이런 경우 무엇을 할 수 있을 까.

이는 Memory Fragmentation 현상으로 판단한다상당히 자잘한 Memory Alloc이 셀 수 없이 반복되면서 메모리 조각화가 발생하는 것이다간혹큰 메모리 덩어리가 할당/해제 되기도 하고 그러면서 메모리 조각화는 더 할당 받을 수 있는 free 영역이 있음에도 불구하고 !addressCheck해보면연속된 여분의 메모리 블럭이 존재하지 않아서 OOM을 유발하게끔 한다이러한 경우에 일차적으로 할 수 있는 것은 1) 어찌됐든불필요한 작고 많은 memory 조각들이 Leak으로 존재하는 부분을 제거해야만 한다이는 DebugDiag Leak tracking을 통해서 Checking될 수 있다. DebugDiag에서 제공하는 Leak 분석에서 제공하는 Callstack 정보는 그 메모리 보유 Size가 크지 않더라도 Allocation Count Check하여 메모리상에 산재됨으로 인한 Fragmentation의 원인이 되진 않는 지 Check 해볼 수 있다.

2) 두 번째는 문서 http://support.microsoft.com/kb/315407 에서 제공하는 registry key, HeapDecommitFreeBlockThreshold 가 도움이 될 수 있다이는 레지스트리에 설정된 값 이상이 되는 경우가 아니면재사용을 위해 decommitted 되지 않는 상태로 유지하는 것이다.

 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager

HeapDecommitFreeBlockThreshold REG_DWORD - 0x00040000 (권고)

 

3)사실 2번째 방법이 Application을 위해서 얼마나 효율적인지 경험해보진 못했다아마도 Windows XP/2003에서 도입된 LFH (Low Fragmentation Heap)을 사용하도록 Application을 구성하는 것이 가장 효율적일지 모르겠다이는 문서 http://msdn.microsoft.com/en-us/library/aa366750.aspx 에도 언급되었지만, HeapSetInformation API를 이용해서 HeapCompatibilityInformation(0) 값을 parameter 전달함으로써 Application Level에서 설정할 수 있다. http://msdn.microsoft.com/en-us/library/aa366705(VS.85).aspx 문서에는 다음과 같은 예제를 확인할 수 있다이는 Application에서 사용하는 모든 Heap을 LFH를 사용하도록 설정할 수 있다.

 

HANDLE heaps[1025];

  DWORD nheaps = GetProcessHeaps(1024, heaps);

 

  for (DWORD i = 0; i < nheaps; i++) {

    ULONG  HeapFragValue = 2;

    HeapSetInformation(heaps[i],

                       HeapCompatibilityInformation,

                       &HeapFragValue,

                       sizeof(HeapFragValue));

  }

이러한 것들이 Memory Fragmentation을 위해 도움이 될 듯 하다.

1 ··· 20 21 22 23 24 25 26 27
블로그 이미지

zzikjh