[실용주의 프로그래머] Mission (2)

다시보려고 쓰기·2022년 3월 28일
0
post-thumbnail

Mission (2)
5장까지 총 23개의 연습문제가 있습니다. 이 중 한 문제를 골라 풀이과정을 작성해 주세요.
연습문제를 읽어 본다.
맘에 드는 연습 문제를 하나 고른다.
연습 문제를 풀고 해설과 참고 문헌을 자세히 쓴다.

💡 연습문제 18.

일부 자바 개발자들은 어떤 객체를 사용한 다음에 반드시 그 객체를 가리켰던 변수를 NULL로 설정한다. 왜 이것이 좋은 생각일까? (p.177)


✅ 풀이 과정

작성하고 있는 코드가 큰 프로그램(메서드)의 일부라면 가능한 모든 객체 사용 후 null을 할당해주어야한다.

예제 1 (null ❌)

public class GCTest {

	private final static int ALLOC_SIZE = (int) (Runtime.getRuntime().maxMemory() * 0.50);

	public void allocate() {

		System.out.println("Before first allocation");
		
		//가용한 메모리의 50% 를 allocate 라는 메서드의 첫번째 지역 변수인 b 에서 할당
		byte[] b = new byte[ALLOC_SIZE];
        
		System.out.println(b);
		System.out.println("After first allocation");
		System.out.println("Before second allocation");
		
		//전혀 하지 않은 후, 두번째 지역변수인 b2 에서 다시 50% 를 할당
		byte[] b2 = new byte[ALLOC_SIZE];
		
		System.out.println(b2);
		System.out.println("After second allocation");

	}

	public static void main(String[] args) {
		new GCTest().allocate();
	}

	}

	public static void main(String[] args) {
		new GCTest().allocate();
	}


예제 1 결과

Before first allocation
[B@7637f22
After first allocation
Before second allocation
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java_lab.GCTest.allocate(GCTest.java:19)
	at java_lab.GCTest.main(GCTest.java:28)

메모리 부족 현상이 나타난다.

예를 들어, 여러 스레드가 동작하여 각각 메서드를 실행하는데, 메서드가 아래와 같은 구조라면,
메서드 호출 ➡️ 객체 여러 개 생성 ➡️ 객체 사용 (이후에는 사용 안함) ➡️ 블럭되는 I/O처리 ➡️ 반환
메서드가 종료되기 전까지 참조하며 사용되지 않는 지역변수들이 쌓이게 된다. 결국 메모리 부족으로 GC가 수행되더라도 OOM(Out Of Memory)가 발생하게 된다.

예제 2 (null ⭕)

public class GCTest2 {

	private final static int ALLOC_SIZE = (int) (Runtime.getRuntime().maxMemory() * 0.50);

	public void allocate() {

			System.out.println("Before first allocation");
			
			byte[] b = new byte[ALLOC_SIZE];
			
			System.out.println("After first allocation b : " + b);
		
			
			b = null;
			
			System.out.println("After assign null to b : " + b);
			System.out.println("Before second allocation b : " + b);
			
			byte[] b2 = new byte[ALLOC_SIZE];
			
			System.out.println("After second allocation b2 : " + b2);
		}
	
		public static void main(String[] args) {
			new GCTest2().allocate();
		}
}

예제 2 결과

Before first allocation
After first allocation b : [B@7637f22
After assign null to b : null
Before second allocation b : null
After second allocation b2 : [B@4926097b

OOM이 발생하지 않는다.


그 외 아래의 참고를 통해 추가로 알게된 것!

null 할당은 GC 가 실행되면 바로 값을 회수해가버리고 이후에 해당 객체를 더이상 사용할 수 없지만,

  1. GC 를 한번 해보고, 메모리가 충분하다면 계속 참조하고 싶다
  2. GC 가 일어나기 전까지만 계속 참조하고 싶다.
  3. finalize 이후에 뭔가 더 처리 하고 싶다.

라는 요구사항을 해결하기 위해 ver 1.2에서 나온 새로운 클래스가 java.lang.ref 패키지이다.

Reference, PhantomReference, SoftReference, WeakReference, ReferenceQueue

java.lang.ref 클래스에는 위의 5가지 클래스가 있다.

  1. GC 를 한번 해보고, 메모리가 충분하다면 계속 참조하고 싶다 (SoftReference)
  2. GC 가 일어나기 전까지만 계속 참조하고 싶다. (WeakReference)
  3. finalize 이후에 뭔가 더 처리 하고 싶다. (PhantomReference)

✅ 참고 링크

https://js2prince.tistory.com/entry/Java-객체-사용후-null-할당-해야하나-말아야-하나


💡 책에 있는 해답

변수를 NULL로 설정하면 그 변수가 가리켰던 객체를 가리키는 포인터의 수가 하나로 줄어든다. 포인터 개수가 0이 되면 그 객체는 가비지 컬렉션 대상이 된다.
실행 시간이 길어서 메모리 사용량이 시간이 지남에 따라 늘어나지도 않도록 신경 써야 하는 프로그램이라면 변수 NULL을 설정하는 것이 중요할 수 있다.

0개의 댓글