클래스를 디자인하다 보면,

많은 경우 생성자의 인자를 통해 멤버변수를 초기화를 하는데,

멤버변수를 추가해야할 일이 생기게 되면,

덩달아서 생성자 또한 변경이나 추가를 해줘야 한다.

 

우선 Java를 예로 들어보자.

 

 

2개의 멤버변수를 갖는 클래스를 예로 들어보자.

public class TestClass

{

    private int m_iVal1 = 0;

    private int m_iVal2 = 0;

 

    public TestClass(int iVal1, int iVal2)

    {

        m_iVal1 = iVal1;

        m_iVal2 = iVal2;

    }

}

 

이 클래스에 멤버변수가 추가된다고 무작정 이렇게 클래스를 변경하는 사람은 없을꺼다.

public class TestClass

{

    private int m_iVal1 = 0;

    private int m_iVal2 = 0;

    private int m_iVal3 = 0;

 

    public TestClass(int iVal1, int iVal2, int iVal2)

    {

        m_iVal1 = iVal1;

        m_iVal2 = iVal2;

        m_iVal3 = iVal3;

    }

}

무작정 이렇게 변경을 해버리면

기존에 인자 2개 생성자 TestClass(1,2)를 사용했던 모든 프로그램들에선 오류가 발생한다.

 

그렇다고 이렇게 똑같은 생장자에 코드만 추가생성을 하면 어떻게 될까?

public class TestClass

{

    private int m_iVal1 = 0;

    private int m_iVal2 = 0;

    private int m_iVal3 = 0;

 

    public TestClass(int iVal1, int iVal2)

    {

        m_iVal1 = iVal1;

        m_iVal2 = iVal2;

    }

 

    public TestClass(int iVal1, int iVal2, int iVal3)

    {

        m_iVal1 = iVal1;

        m_iVal2 = iVal2;

        m_iVal3 = iVal3;

    }

}

이렇게 수정했을시 또다른 문제가 발생할 수 있다.

첫째 문제 불필요한 소스코드 작성이고,

둘째 문제는 TestClass(1, 2)와 TestClass(1,2,3)간 무결성 오류가 생길 수 있다는 것이다.

 

시간이 지나고 지나서, 생성자에서 멤버변수 초기화부분을 수정하게 된다면...

매번 TestClass(1, 2)와 TestClass(1,2,3)를 똑같이 수정해주거나,

한쪽에서 수정을 빼먹는다면 무결성 오류가 발생할 수 있는것이다.

 

따라서 이렇게 수정하는 것이 가장 깔끔하다고 할 수 있다.

public class TestClass

{

    private int m_iVal1 = 0;

    private int m_iVal2 = 0;

    private int m_iVal3 = 0;

 

    public TestClass(int iVal1, int iVal2)

    {

        m_iVal1 = iVal1;

        m_iVal2 = iVal2;

    }

 

    public TestClass(int iVal1, int iVal2, int iVal3)

    {

        this(iVal1, iVal2);    //이 코드앞에 다른 코드를 추가하면 컴파일 오류가 생긴다.

        m_iVal3 = iVal3;

    }

}

항상 주의해야 할 것은 생성자에서 또다른 생성자를 호출할때,

Body의 가장 첫부분에 생성자를 호출해야한다는 것이다.

생성자가 클래스를 초기화 하는 놈인데, 클래스 초기화도 전에 다른 것을 수행하면 안되기 때문이다.

아주 간단한 Print문이라도 예외없이 Java컴파일는 오류를 반환한다.

 

 

 

자 이번엔 C#을 예로 들어보자.

 

 

위와 똑같은 구분을 C#으로 작성해보면 에러가 발생한다.

public class TestClass

{

    private int m_iVal1 = 0;

    private int m_iVal2 = 0;

    private int m_iVal3 = 0;

 

    public TestClass(int iVal1, int iVal2)

    {

        m_iVal1 = iVal1;

        m_iVal2 = iVal2;

    }

 

    public TestClass(int iVal1, int iVal2, int iVal3)

    {

        this(iVal1, iVal2);    //여기서 오류가 발생한다.

        m_iVal3 = iVal3;

    }

}

C#에서는 생성자 Body안에서 생성자를 호출하는 것이 문법적으로 막혀있다.

Java에서는 Body안에 호출할 수는 있지만, 가장 처음에 호출하게 되었있는데,

C#에서는 아예 문법적으로 이를 제약하여 Body구문 이전에 이를 호출해야한다.

 

C#생성장에서 다른 생성자를 호출하려면 이렇게 해야한다.(C++을 써왔다면 익숙한 구문)

public class TestClass

{

    private int m_iVal1 = 0;

    private int m_iVal2 = 0;

    private int m_iVal3 = 0;

 

    public TestClass(int iVal1, int iVal2)

    {

        m_iVal1 = iVal1;

        m_iVal2 = iVal2;

    }

 

    public TestClass(int iVal1, int iVal2, int iVal3) : this(iVal1, iVal2)

    {

        m_iVal3 = iVal3;

    }

}


Google AdSense

간만에 블로깅이다.
오늘은 .NET Framework의 가비지콜랙터에 대해 끄적여볼껀데,
가비지콜랙터, 메모리누수에 대해 눈꼽만큼이라도 고민해 본적이 있는 어린이들에게 도움이 됐으면 한다.

※여기서 [객체], [인스턴스변수], [포인터]는 모두 같은 의미이다.※


C나 C++에서는 힙 메모리를 할당한 후 그것을 관리하던 포인터를 잃어리면...
해당 쓰레드가 종료되기 전까지 세어나간 메모리를 돌려놓을 방법이 없다.
이것이 바로 일반적으로 메모리누수라고 부르는 것이다.

엄밀히 말하자면...
Java, C#으로 넘어오면서 프로그래머들은 메모리 누수로 부터 해방됐다.
바로 가비지콜랙터라는 놈이 힙 메모리를 자동으로 반환해주기 때문이다.

그럼에도 불구하고 아직도 우리는 메모리누수라는 말을 가끔 쓰고 있다.
그럼 Java나 C#을 사용하면서 얘기하는 메모리누수라는 것은 무엇이냐?
.....
여기서 메모리누수라는 것은.... 반환되어야할 시기에 반환되지 않는 메모리를 얘기하는 것이다.

가비지콜랙터는 객체(포인터, 인스턴스변수)가 NULL로 설정되면 사용하던 힙메모리를 자동으로 반환해준다.
물론 NULL을 명시적으로 주지 않아도,
함수내에서 생성했던 객체들은 함수의 활동이 끝나서 스택에서 퇴출될때 함께 반환된다.
(알아둬야 할 것은 NULL로 설정 되었다고해서 가비지콜랙터가 즉시 반환해주지는 않는다. 언젠가는 반환해주지만, 가비지콜랙터가 자주 출동하면 시스템이 느려진다. 이건 나중에 따로 포스팅을 해볼 생각이다.)

어쨋든 포인터를 NULL로 설정하지 않으면 해당 프로세스, 쓰레드, 함수가 종료되기 전까지는
가비지콜랙터가 메모리를 반환할 방법이 없다.
이런 것들이 쌓이는 것이 여기서 얘기하는 메모리누수인데....
가장 흔한 경우가 바로 활동시간이 아주 기~인 객체가 여러 객체들과 짝지어진 경우이다.
한두번 쓰이고 반환되어야할 많은 객체들이 활동시간이 긴 객체와 함께 오래오래 살아남아 문제가 된다.
자신을 참조하는 객체가 계속 살아있으니, 참조당하는 객체들이 NULL로 될수 없고,
NULL이 아닌 객체들을 가비지콜랙터가 반환할 수는 없으니 말이다.

따라서 메모리누수를 막기위해서는
첫째, 활동기간이 긴 객체와 짧은 객체는 되도록 참조하는 것을 피하고,
둘째, 사용이 끝난 포인터는 즉시 NULL로 할당해주는 코딩습관이 필요하다.
  괜히 순환문이 있는 길고 긴 함수가 종료되거나, 호출객체의 활동이 끝때까지 그대로 놔두면...
  언젠가 큰 화를 불러올지도 모른다.
셋째, Full 가비지콜랙터가 출동하는 것을 막는 것이 좋다.
  흠, 이건 메모리누수보단 Full 가비지콜랙터의 작동때문에 시스템이 느려지는 것을 막기위함인데...
  활동기간이 긴 객체는 최소한의 메모리만 사용하도록 하는 것이 좋다.

Google AdSense


.NET에서 사운드 볼륨을 조절하는 방법에 대해 적어본다.
볼륨 조절은 하드웨어(사운드카드) 제어에 속하는데,
닷넷에서는 하드웨어 제어 수단을 제공하지 않는다.

따라서 C#에서는 윈도우즈에서 제공하는 Win32 API를 사용해야한다.

거두절미하고,
사운드 제어를 위해 작성한 SoundUtils클래스 파일을 첨부한다.

파일 ==> <== 여기

첨부된 클래스를 간단하게 설명하자면...
public static으로 제공되는 함수는 아래의 4가지 인데...
GetVolume, SetVolumne, SetVolumePercent, PlaySound

볼륨을 50%로 만들고 싶으면
첨부파일을 프로젝트에 추가시킨후
자신의 소스에서 아래와 같이 하면된다.

Nagarry.SoundUtils.SetVolumePercent(50);


도움이 됐다면 리플 좀 남겨주시오!

Ps. 첨부된 소스코드는 시스템볼륨을 조절 하고있습니다.
확인해보니 비스타와 윈7에선 시스템볼륨조절이 막혔고, 미디어볼륨만 조절가능하다네요 ^_~@
Google AdSense

+ Recent posts