자바 가 어떻게 자원 회수 보완 을 하 는 지 에 대해 논 하 다.

자바 를 배 우 는 과정 에서 우 리 는 한 대상 의 회수,특히 자원 유형 에 대해 자주 이야기 합 니 다.표시 되 지 않 은 닫 히 면 대상 이 회수 되 고 자원 유출 이 발생 한 것 을 설명 합 니 다.자바 자 체 는 이러한 상황 을 방지 하기 위해 닫 히 지 않 은 자원 을 합 리 적 으로 회수 할 수 있 도록 보증 을 섰 다.
최종 화 회수
finalize 방식 은 자바 대상 이 회수 되 었 을 때 발생 하 는 방법 입 니 다.자바 의 많은 자원 대상 은 finalize 에 담보 방법 을 썼 습 니 다.

  /**
   * Ensures that the <code>close</code> method of this file input stream is
   * called when there are no more references to it.
   *
   * @exception IOException if an I/O error occurs.
   * @see    java.io.FileInputStream#close()
   */
  protected void finalize() throws IOException {
    if ((fd != null) && (fd != FileDescriptor.in)) {
      /* if fd is shared, the references in FileDescriptor
       * will ensure that finalizer is only called when
       * safe to do so. All references using the fd have
       * become unreachable. We can call close()
       */
      close();
    }
  }
위 는 FileInputStream 의 finalize 방법 입 니 다.방법 이 호출 될 때 파일 설명자 가 존재 하 는 지 확인 하고 존재 하면 close 방법 을 사용 합 니 다.자원 의 회 수 를 확보 하 다.
finalize 방법 은 우리 가 자바 를 배 울 때 재 작성 하 는 것 을 추천 하지 않 고 복잡 한 논 리 를 쓰 는 것 을 추천 하지 않 습 니 다.주로 gc 를 배 울 때 이 방법 을 사용 하기 때 문 입 니 다.만약 에 실행 하 는 내용 이 너무 많 으 면 gc 가 길 어 집 니 다.프로그램의 정상 적 인 운행 에 영향 을 주다.그리고 여기 도 간단 한 담보 일 뿐 이 야.대부분의 희망 은 코드 를 작성 하 는 사람 이 close 를 호출 할 수 있 습 니 다.이렇게 하면 닫 힌 코드 를 제대로 호출 하지 않 고 판단 할 때 끝난다.
클 리 너 회수
DirectByte Buffer 에 서 는 클 리 너 대상 을 사용 해 보완 했다.

   unsafe.setMemory(base, size, (byte) 0);
    if (pa && (base % ps != 0)) {
      // Round up to page boundary
      address = base + ps - (base & (ps - 1));
    } else {
      address = base;
    }
    cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
    att = null;
자원 을 신청 하면 Deallocator 대상 을 만 듭 니 다.

 private static class Deallocator
    implements Runnable
  {

    private static Unsafe unsafe = Unsafe.getUnsafe();

    private long address;
    private long size;
    private int capacity;

    private Deallocator(long address, long size, int capacity) {
      assert (address != 0);
      this.address = address;
      this.size = size;
      this.capacity = capacity;
    }

    public void run() {
      if (address == 0) {
        // Paranoia
        return;
      }
      unsafe.freeMemory(address);
      address = 0;
      Bits.unreserveMemory(size, capacity);
    }

  }

Deallocator 의 run 방법 에서 자원 의 방출 이 진행 되 었 습 니 다.실행 시 기 는 클 리 너 에 의 해 촉발 된다.
클 리 너 는 팬 텀 레 퍼 런 스 의 하위 클래스 이 고,팬 텀 레 퍼 런 스 는 레 퍼 런 스 의 하위 클래스 다.
그 중 에 Reference Handler 가 있어 요.

 private static class ReferenceHandler extends Thread {
그의 run 방법 은 cleaner 의 clean 방법 을 호출 하 는 것 이다.이 스 레 드 는 정적 블록 에서 작 동 되 었 다.

    Thread handler = new ReferenceHandler(tg, "Reference Handler");
    /* If there were a special system-only priority greater than
     * MAX_PRIORITY, it would be used here
     */
    handler.setPriority(Thread.MAX_PRIORITY);
    handler.setDaemon(true);
    handler.start();
    SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
      @Override
      public boolean tryHandlePendingReference() {
        return tryHandlePending(false);
      }
    });
이와 함께 Shared Secrets 에 자바 랑 RefAccess 를 설정 했다.
clean 방법 을 호출 하 는 과정 은 try Handle Pending 에서 중요 합 니 다.

 static boolean tryHandlePending(boolean waitForNotify) {
    Reference<Object> r;
    Cleaner c;
    try {
      synchronized (lock) {
        if (pending != null) {
          r = pending;
          // 'instanceof' might throw OutOfMemoryError sometimes
          // so do this before un-linking 'r' from the 'pending' chain...
          c = r instanceof Cleaner ? (Cleaner) r : null;
          // unlink 'r' from 'pending' chain
          pending = r.discovered;
          r.discovered = null;
        } else {
          // The waiting on the lock may cause an OutOfMemoryError
          // because it may try to allocate exception objects.
          if (waitForNotify) {
            lock.wait();
          }
          // retry if waited
          return waitForNotify;
        }
      }
    } catch (OutOfMemoryError x) {
      // Give other threads CPU time so they hopefully drop some live references
      // and GC reclaims some space.
      // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
      // persistently throws OOME for some time...
      Thread.yield();
      // retry
      return true;
    } catch (InterruptedException x) {
      // retry
      return true;
    }
wait ForNotify 가 true 일 때 회수 대상 이 없 을 때 차단 에 들 어가 서 ooe 를 기다린다.바깥쪽 은 사순환 으로 다시 호출 되 고 다음 에 들 어 올 때 클 린 을 출발 할 수 있 습 니 다.
Reference Handler 는 관리 체제 의 일종 이다.
또 하 나 는 Shared Secrets 가 try Handle Pending(false)을 호출 하 는 것 이다.
다른 클래스,bits 에서

  final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();

    // retry while helping enqueue pending Reference objects
    // which includes executing pending Cleaner(s) which includes
    // Cleaner(s) that free direct buffer memory
    while (jlra.tryHandlePendingReference()) {
      if (tryReserveMemory(size, cap)) {
        return;
      }
    }

reserve Memory 를 할 때 Shared Secrets 에서 try Handle Pending(false)을 호출 합 니 다.이곳 에 서 는 또 변 형 된 회수 가 진행 되 었 다.
작은 매듭
자바 재 활용 두 가지 메커니즘.하 나 는 finalize,하 나 는 Cleaner.그 중에서 클 리 너 일 부 는 oome 에 의존 하여 회 수 를 촉발 하고 일 부 는 reserveMemory 에서 회 수 를 한다.
자바 가 자원 회수 보완 을 어떻게 하 는 지 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 자원 회수 보완 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

좋은 웹페이지 즐겨찾기