ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Chapter 2. Java Memory & Variable Type
    Java 2021. 7. 4. 19:02

    1. Memory Structure

    • Heap Area : 런타임 도중 생성되는 영역으로 JVM에 의해 메모리 할당/해제가 빈번히 일어난다.
    • Method Area : 전역변수, 멤버 변수, 스태틱 변수, 클래스 정보 등이 포함된다. static 변수는 클래스 당 하나가 생성되며 모든 객체들이 공유한다. 클래스 로딩 시 생성되며 클래스가 해제할 때 소멸된다. 
    • JVM Stack : LIFO 구조로 함수와 관련된 정보가 포함된다. 함수 리턴 주소, 파라미터 정보, 지역 변수 등이 포함된다.
    • Native Method Stack : C, C++ 등 Native 언어에 필요한 정보들이 포함된다.
    • PC Register : 다음 수행할 Instruction 주소가 포함된다.

     

    2. Primive Type vs Reference Type

    Primitive Type은[기본] int, double, character 등 기본 타입을 의미하고 Reference Type은[참조] String, 사용자에 의해 생성된 객체 타입을 의미한다. 또한 null 값은 reference type만 가질 수 있다.

     

    멤버 변수, 지역 변수등 조건에 맞게 method, stack에 생성된다. 이때 primitive type은 해당 메모리에 값이 저장되고, reference type은 값을 나타내는 주소 값을 저장한다. 따라서 reference type의 논리적 값을 비교하고 싶다면 equals meothd를 overriding 하여 처리해야한다.

     

    예외적으로 string a = "123"과 string b= "123"을 == 비교한다면 다른 reference type과 달리 같은 값이라고 나오는데 이유는 string constatnt pool 영역에 "123"이 생성되고 a와 b 모두 constant pool 영역에 "123"을 가리키고 있기 때문이다. 만약 new에 의해 생성된 객체를 비교할 때는 equals method를 Overriding하여 처리해야한다.

     

    3. call by value vs call by reference

    함수 호출시 전달 되는 '값을 복사'하여 전달하면 call by value라 불리고, 변수의 '참조 값' 혹은 '주소 값'을 전달하면 call by reference type이라고 불린다. call by value는 복사된 값이 전달되어 해당 함수에서 수정되더라도 원래 값에 영향을 끼치지 않기 때문에 '안전성'의 장점이 있다. 반면 call by reference는 참조 값이 전달되어  해당 함수에서 수정하면 원래 값에 영향을 끼치는 특징이 존재한다.

     

    아래 그림에서 C++은 주소 값을 넘길 때 해당 변수의 주소 값을 넘겨 다른 함수에서도 원래의 값을 변경 할 수 있다. 반면 Java는 Reference Type의 경우 변수가 가리키는 즉, heap 영역에 할당된 '값에 주소 값'을 넘겨 새로운 값을 아래처럼 할당 받더라도 원래 값을 변경하지 않는다. 그렇다고 다른 함수에서 원래 값을 변경할 수 없음을 의미하는것은 아니다. 아래 코드에서 tmp = new Object()가 아닌 tmp.value = "456"이런식으로 변경하여 즉, heap 영역을 가리키는 '객체 안에 정보'를 수정하면 원래 값을 바꿀 수 있다.

     

     

     

    4. mutable vs immutable type

    mutable : 객체 생성 후 상태를 변경할 수 있다. string을 제외한 reference type이 이에 해당한다.

    immutable : 객체 생성 후 상태를 변경할 수 없다. primitive type, string type이 이에 해당한다.

     

    immutable 타입은 객체 생성후 변경될 때마다 새로운 값을 '새로 생성'하므로 '안정성'의 장점이 있는 반면 값의 업데이트시 mutable 변수보다 느린 단점이 존재한다. 일반적으로 mutable한 타입이 속도가 더 빠르다.

     

    만약 string + string + --- 연산이 많을 경우 string 타입보다는 mutable한 타입의 stringbuffer stringbuilder을 사용하는것이 더욱 좋으며 이 둘 사이에서도 동기화 지원여부에 따라 어떤걸 선택할지 골라야한다.

     

    primitive type은 immutable 타입으로 mutable로 바꾸고 싶다면 Wrapper Class로 변경하여 사용하면된다. Integer 등

     

    5. 깊은 복사 vs 얕은 복사

    객체를 복사할 때 '참조 값'을 복사하는 얕은 복사와 '실제 값'을 복사하는 깊은 복사가 있다.

    • 얕은 복사 : primitive type은 값을 복사하고 reference type은 주소 값을 복사한다.
    • 깊은 복사 : primitive type은 값을 복사하고 reference type 또한 값을 복사한다.

     

    Example Code

       Test A;

       Test B;

       A=B;

     

    위의 코드와 아래 사진을 함께 살펴보자. 얕은 복사의 경우 사진처럼 Reference Type을 '공유'하게 된다. 즉, A에서 name의 값을 변경하면 B에서도 해당 값이 같이 변경하게 된다. 하지만 깊은 복사는 아래 사진처럼 Reference Type 역시 '각각' 존재하여 A에서 name 값을 변경하더라도 B에서 값 변경이 일어나지 않는다.

     

    또한 얕은 복사의 경우 A에서 소멸자가 일어나 refence type의 name을 소멸했고 이후, B에서 다시 소멸자가 일어난다면 이미 제거된 name을 다시 소멸하여 문제가 발생할 수 있다. 따라서 특별한 경우가 아니라면 clone()하여 즉 copy하여 깊은 복사를 하는것이 더욱 좋다.

     

     

    'Java' 카테고리의 다른 글

    Chapter 3. Java Virtual Machine  (0) 2021.07.04
    Chapter 1. Object Oriented Programming  (0) 2021.07.04
    기본기  (0) 2020.08.26
Designed by Tistory.