참조타입(String과 GarbageCollection으로 설명)
오늘은 참조타입에 대해서 알아보겠습니다.
이전에 기본타입이 아닌 모든 것들은 참조타입이라고 말씀드렸습니다.
저희가 알고 있는 String도 기본타입이 아닌 참조타입이란걸 알고 계시나요?
이번에는 참조타입에 대해서 알아보도록 하겠습니다.
먼저 class 2개를 이용해서 설명드리겠습니다.
main함수가 밑에 있더라도 자바는 main함수를 가장 먼저 실행시킵니다.
A obj = new A( ); 는 obj라는 이름으로 A를 쓰겠다는 것이고 obj.b(true)를 하면
class A에 있는 boolean형 b에 대해 input parameter를 true로 주겠다는 뜻입니다.
이러한 일이 가능한 것은 바로 객체지향의 특성으로 참조가 되고 있기 때문입니다.
이전에 기본타입이 아닌 모든 것들은 참조타입이라고 말씀드렸습니다.
저희가 알고 있는 String도 기본타입이 아닌 참조타입이란걸 알고 계시나요?
이번에는 참조타입에 대해서 알아보도록 하겠습니다.
먼저 class 2개를 이용해서 설명드리겠습니다.
main함수가 밑에 있더라도 자바는 main함수를 가장 먼저 실행시킵니다.
A obj = new A( ); 는 obj라는 이름으로 A를 쓰겠다는 것이고 obj.b(true)를 하면
class A에 있는 boolean형 b에 대해 input parameter를 true로 주겠다는 뜻입니다.
이러한 일이 가능한 것은 바로 객체지향의 특성으로 참조가 되고 있기 때문입니다.
이번에는 String에 대해 보도록 하겠습니다.
String s1 = new
String(“자바” );
//String을 reference data type
// 인스턴스영역에 String객체 생김
//Stack영역에 s1
200번지 생성 -> 인스턴스 String @200가르킴
String s2 = new
String(“자바”);
//그럼 stack에 s2 300번지 생성
// 인스턴스에 String 객체 1개 더 생성(@300번지) 가르키게됨
즉, s1과 s2는 똑같은 "자바"라는 문자열을 가지고 있지만 둘은 주소값이 다른 객체입니다.
(s1==s2)를 프린트하면 false가 나옵니다. 주소값을 의미하기 때문이죠.
똑같은 문자열을 이용하면서 객체의 주소값이 다르면 메모리가 낭비되겠죠?
String에선 이러한 일이 종종 있기 때문에 String에 한해서 예외규칙을 만들게 됩니다.
그 방법은 바로 new를 안쓰는 방법이죠
String s3 = "자바";
String s4 = "자바";
String에 한해서는 이렇게도 표현이 가능합니다.
""를 사용하면 이전에 메모리 구조에서 보여드린 String Literal Pool 기억나시죠?
다시 설명 드리자면,
String s3 = "자바";
String s4 = "자바";
new로 인스턴스 영역에서 공간을 안만들고 바로 “”만나게 됩니다.
String을 new가 아닌 literal로 바로 만들 경우 String literal pool 영역으로 바로 가는데 이 영역에 c-value-comparator라는 것을 만나게 됩니다.
(c-value-comparator : 문자 값을
비교하는 기능을 가진 녀석)
이 영역에 어떤 문자열이 있으면 이와 똑같은 literal을 찾게됩니다.
만약 없다면 공간을 하나 할당받는 것이죠.
String literal pool에서 \u0000으로 2공간 할당합니다.
\u0000은 이전에 char의 초기값으로
공백(스페이스)를 의미한다고 했죠?
[자][바] 라는 2글자이기 때문에 char로 2공간을 가진 것입니다.
아무튼, m/a에서 만들어진 것을 가르키게되고 [자][바] 2글자가 들어갑니다.
그 다음 주소값이 생깁니다.(편의상 @1)
그렇다면 주소값 1번지의 이름이 s1이 되고 stack에서 String literal pool 가르키게됩니다.
String s4 = “자바”; 실행하면 바로 String literal pool로 가게되고
여기선 바로 만들어진 곳(s3)을 가르키게 됩니다.
즉,
s3와 s4는 이번엔 같은 주소 값을 가르키게 되는 거죠
메모리 효율성과 퍼포먼스는 “”가 더 좋기에 String으로 생성 할 땐 new가 아닌 ""를 쓰시는게 좋습니다~
그렇다면 s1=null; 을 하면 어떻게 될까요?
stack영역의 s1의 주소값이 null이 되서 끊기고 instance에 있는 기존 200번지 값은 garbage가 됩니다. 이걸 지운다고해서 m/a의 일반영역에서 만들어진 것은 안지워지구요. 그 이유는 다른 곳에서 가르킬 수도
있기 때문에 위험하기 때문입니다.
그럼 이제 오늘 배운 (String literal pool)에 대해서 다시 살펴보죠.
s3=null; 을 하면 String literal pool영역도 연결이 끊깁니다.
s4=null;을 하면 역시 또 끊깁니다.
그럼 이것도 Garbage일까요? 아뇨 여기선 Garbage가 아닙니다!
왜냐하면 String
s5 = “자바”를 또 하면 바로 String literal pool영역의 @1를 가르키게 되기 때문입니다. 그리고 이 때 m/a영역의 안지워졌던 부분도 연결되구요.
(원칙대로라면 메소드도 객체(데이터와 메소드의 조합)가
각각 가져야하죠.
그런데 다시 생각해보면 메소드라는게 너의 해야할 일(작업지시서)이고 똑같은 템플릿으로 나왔다면 작업지시서가
다 똑같은데 작업지시서를 계속 만드는 것은 비효율적으로 됩니다. 똑같은
작업지시서(메소드)니 이 사람 저사람 모두 똑같은걸 보게 만든 것으로 생각하시면 되겠습니다.
댓글 없음: