전 포스트에서 다뤘듯이 Java는 오직 Call by Value 방식으로만 동작한다.
자세한 내용은 하단 링크 참고
Java가 이렇게 설계된 데에는 몇 가지 중요한 이유와 장점이 있다.
지금부터 그 이유와 장점에 대해 상세하게 알아보자!
Call by Reference 방식은 함수 내에서 변수의 값을 직접 수정할 수 있기 때문에, 코드가 복잡해지고 변수 상태를 예측하기 어려워질 수 있다.
반면 Java는 Call by Value를 통해 원본 데이터를 직접 수정할 수 없도록 보호하여, 함수 내에서의 변경이 호출자의 변수에 영향을 미치지 않도록 설계되었다.
이를 통해 예측 가능하고 디버깅하기 쉬운 코드를 작성할 수 있다.
Java는 메모리 관리를 단순화하고 효율적으로 하기 위해 Garbage Collection 을 사용한다.
📃 가비지 컬렌션 동작 방식
GC는 런타임 데이터 영역 중 힙 영역에서만 수행된다.
스택 영역에 할당된 데이터는 함수 호출이 끝나면 자동으로 해제되므로 GC가 필요하지 않다.
Java의 Call by Value 방식은 함수 호출 시 값을 복사하여 전달하므로, 스택과 힙 메모리의 역할이 명확하게 분리된다.
원시 타입은 스택에 복사되고, 참조 타입은 힙에 할당된 객체의 주소값이 복사된다.
💡 이로 인해 함수 호출 시 객체의 상태는 수정할 수 있어도, 참조 자체는 바뀌지 않아 불필요한 참조 변경으로 인한 메모리 누수나 참조 오류를 줄일 수 있는 것이다.
또한 Java에서는 메모리 누수나 참조 오류가 상대적으로 덜 발생하는데,
이는 GC가 사용되지 않는 메모리를 자동으로 정리해주기 때문이다.
반면, Call by Reference 방식을 사용하는 C++같은 언어에서는 원본 변수나 객체의 참조를 잘못 관리할 경우 메모리 누수나 참조 오류가 발생할 수 있다.
(C++ 에서는 직접 메모리 관리를 해야 하고, 잘못된 메모리 주소를 참조하거나, 더 이상 필요 없는 데이터를 적절히 해제하지 않으면 메모리 누수가 발생할 수 있다)
Java는 순수한 객체 지향 언어로 설계되었다.
Java에서는 객체를 다룰 때, 객체의 상태는 수정할 수 있지만 참조 자체는 수정할 수 없게 만들었다.
이는 Call by Reference와 유사한 효과를 내지만, 참조 자체의 변경을 막아 불필요한 혼란을 방지한다.
💡 Java가 이런 방식으로 설계된 이유는 객체의 상태만을 관리하고, 참조 변수 자체의 변경은 제한함으로써 더 안전한 코드 구조를 제공하기 위함이다.
Call by Value는 기본적으로 데이터를 복사하여 전달하므로 큰 데이터를 전달할 때 성능 문제가 있을 수 있지만,
Java는 참조 타입에 대해서는 주소값만 복사하므로 메모리 상에서 실제 데이터를 복사하지 않고도 객체의 상태를 관리할 수 있다.
이로 인해 대용량 데이터를 처리할 때 성능을 어느 정도 보장하면서도 참조에 의한 데이터 변경을 효과적으로 방지할 수 있다.
Java가 Call by Value만을 채택한 이유는 안정성, 예측 가능성, 메모리 관리의 효율성, 성능 최적화와 같은 장점들을 제공하기 위함이다.
Java는 이 방식을 통해 개발자가 코드에서 예측 가능한 방식으로 데이터와 객체를 다룰 수 있도록 하면서, 불필요한 참조 변수의 복잡성을 제거하여 오류 가능성을 최소화하도록 설계되었다.