Java 및 Android 개발에서 WeakReference를 사용하는 방법은 무엇입니까?


166

나는 2 년 동안 자바 개발자였습니다.

그러나 코드에 WeakReference를 작성하지 않았습니다. WeakReference를 사용하여 응용 프로그램, 특히 Android 응용 프로그램을보다 효율적으로 만드는 방법은 무엇입니까?


안드로이드에 대한 차이점이있을 수 있습니다 : stackoverflow.com/questions/299659/…
Pacerier

답변:


229

WeakReferenceAndroid에서 a 를 사용하는 것은 평범한 Java에서 사용하는 것과 다르지 않습니다. 다음은 자세한 설명을 제공하는 훌륭한 안내서입니다 . 약한 참조 이해 .

객체에 대한 참조가 필요할 때마다 하나를 사용하는 것을 고려해야하지만 가비지 수집기에서 객체를 보호하기 위해 해당 참조를 원하지 않습니다. 전형적인 예는 메모리 사용량이 너무 많을 때 (종종로 구현 됨 WeakHashMap) 가비지 수집하려는 캐시입니다 .

확인하시기 바랍니다 SoftReferencePhantomReference뿐만 아니라.

편집 : Tom은으로 캐시를 구현하는 것에 대해 약간의 우려를 제기했습니다 WeakHashMap. 다음은 문제를 설명하는 기사입니다. WeakHashMap은 캐시가 아닙니다!

Tom은 캐싱 으로 인한 Netbeans 성능 저하에 대한 불만 이 있었다고 생각 WeakHashMap합니다.

나는 여전히 캐시를 구현 한 WeakHashMap다음 그것을 사용하여 직접 구현 한 캐시와 비교 하는 것이 좋은 학습 경험이라고 생각합니다 SoftReference. 실제 환경에서는 Apache JCS 와 같은 타사 라이브러리를 사용하는 것이 더 적합하므로 이러한 솔루션 중 하나를 사용하지 않을 것입니다 .


15
아니! 아니! 아니! WeakHashMap캐시로 사용되는 것은 치명적입니다. 항목을 작성하자마자 제거 할 수 있습니다. 테스트 할 때는 발생하지 않지만 사용 중일 때는 잘 될 수 있습니다. 이것에 의해 NetBeans를 100 % 효과적으로 CPU 정지시킬 수 있습니다.
Tom Hawtin-tackline

3
@Tom 내 답변을 업데이트했습니다. 공정하게 WeakHashMap
말해서

1
dbyrne의 훌륭한 답변. 고마워 나는 크리스가이 대답을 받아들이지 않을 이유가 없다.

@dbyrne GridView, ImageView 또는 BaseAdapter와 같은 활동에서 객체를 사용하고 있습니다. onDestroy 메소드에서 활동을 완료 할 때 Weak / SoftReferences를 사용하여이 오브젝트로 무언가를 수행해야합니까? 아니면 시스템이이 개체의 메모리를 자동으로 청소합니까?
beni

4
java.net에 대한 링크
끊기

64

[EDIT2] 다른 좋은 예를 찾았습니다 WeakReference. 비트 맵 표시 의 UI 스레드 페이지에서 비트 맵 처리 효율적으로 훈련 안내서, WeakReferenceAsyncTask에서 한 가지 사용법을 보여줍니다 .

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    private final WeakReference<ImageView> imageViewReference;
    private int data = 0;

    public BitmapWorkerTask(ImageView imageView) {
        // Use a WeakReference to ensure the ImageView can be garbage collected
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Integer... params) {
        data = params[0];
        return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
    }

    // Once complete, see if ImageView is still around and set bitmap.
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

그것은 말합니다

ImageView에 대한 WeakReference는 AsyncTask가 ImageView 및 그 참조가 가비지 수집되는 것을 막지 않도록합니다 . 작업이 완료 될 때 ImageView가 계속 유지된다는 보장은 없으므로 onPostExecute ()에서 참조를 확인해야합니다. 예를 들어 사용자가 활동에서 벗어나거나 작업이 완료되기 전에 구성 변경이 발생하면 ImageView가 더 이상 존재하지 않을 수 있습니다.

행복한 코딩!


[편집] facebook-android-sdkWeakReference 에서 정말 좋은 예를 찾았습니다 . ToolTipPopup 클래스는 앵커 뷰 위에 툴팁을 표시하는 간단한 위젯 클래스입니다. 스크린 샷을 찍었습니다.

멋진 스크린 샷

수업은 정말 간단하고 (약 200 줄) 볼 가치가 있습니다. 그 수업에서WeakReference 클래스는 앵커 뷰에 대한 참조를 보유하는 데 사용됩니다. 툴팁 인스턴스가 앵커 뷰보다 오래 지속되는 경우에도 앵커 뷰를 가비지 수집 할 수 있기 때문에 완벽합니다.

행복한 코딩! :)


한 가지 실례를 공유하겠습니다 WeakReference수업의 . 안드로이드 프레임 워크 위젯의 작은 코드 스 니펫입니다 AutoCompleteTextView.

요컨대, WeakReference 수업은 View 이 예제에서 메모리 누수 를 방지하기 위해 객체를 .

중첩 된 클래스 인 PopupDataSetObserver 클래스를 복사하여 붙여 넣기 만하면됩니다. AutoCompleteTextView 됩니다. 정말 간단하고 의견은 수업을 잘 설명합니다. 행복한 코딩! :)

    /**
     * Static inner listener that keeps a WeakReference to the actual AutoCompleteTextView.
     * <p>
     * This way, if adapter has a longer life span than the View, we won't leak the View, instead
     * we will just leak a small Observer with 1 field.
     */
    private static class PopupDataSetObserver extends DataSetObserver {
    private final WeakReference<AutoCompleteTextView> mViewReference;
    private PopupDataSetObserver(AutoCompleteTextView view) {
        mViewReference = new WeakReference<AutoCompleteTextView>(view);
    }
    @Override
    public void onChanged() {
        final AutoCompleteTextView textView = mViewReference.get();
        if (textView != null && textView.mAdapter != null) {
            // If the popup is not showing already, showing it will cause
            // the list of data set observers attached to the adapter to
            // change. We can't do it from here, because we are in the middle
            // of iterating through the list of observers.
            textView.post(updateRunnable);
        }
    }

    private final Runnable updateRunnable = new Runnable() {
        @Override
        public void run() {
            final AutoCompleteTextView textView = mViewReference.get();
            if (textView == null) {
                return;
            }
            final ListAdapter adapter = textView.mAdapter;
            if (adapter == null) {
                return;
            }
            textView.updateDropDownForFilter(adapter.getCount());
        }
    };
}

그리고 PopupDataSetObserver 어댑터 설정에 사용됩니다.

    public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
    if (mObserver == null) {
        mObserver = new PopupDataSetObserver(this);
    } else if (mAdapter != null) {
        mAdapter.unregisterDataSetObserver(mObserver);
    }
    mAdapter = adapter;
    if (mAdapter != null) {
        //noinspection unchecked
        mFilter = ((Filterable) mAdapter).getFilter();
        adapter.registerDataSetObserver(mObserver);
    } else {
        mFilter = null;
    }
    mPopup.setAdapter(mAdapter);
}

마지막 한가지. 또한 WeakReferenceAndroid 애플리케이션 의 실제 예제를 알고 싶었고 공식 샘플 애플리케이션에서 샘플을 찾을 수있었습니다. 그러나 나는 실제로 그들의 사용법 중 일부를 이해할 수 없었습니다. 예를 들어 ThreadSampleDisplayingBitmaps 응용 프로그램 WeakReference은 해당 코드에서 사용하지만 여러 테스트를 실행 한 후 null참조 된 뷰 객체가 가비지 수집 된 어댑터가 아닌 어댑터에서 재활용되므로 get () 메서드가 결코 반환하지 않는 것으로 나타났습니다 .


1
훌륭한 예에 감사드립니다-나는 이것이 이것이 질문에 대한 대답이라고 생각합니다. 건배!
Ackshaey Singh

트윗 담아 가기 :)
김준호

16

다른 답변 중 일부는 불완전하거나 지나치게 길어 보입니다. 일반적인 답변은 다음과 같습니다.

Java 및 Android에서 WeakReference를 사용하는 방법

다음 단계를 수행 할 수 있습니다.

  1. 만들기 WeakReference변수
  2. 약한 참조 설정
  3. 약한 참조를 사용하십시오

암호

MyClass에 대한 약한 참조가 AnotherClass있습니다.

public class MyClass {

    // 1. Create a WeakReference variable
    private WeakReference<AnotherClass> mAnotherClassReference;

    // 2. Set the weak reference (nothing special about the method name)
    void setWeakReference(AnotherClass anotherClass) {
        mAnotherClassReference = new WeakReference<>(anotherClass);
    }

    // 3. Use the weak reference
    void doSomething() {
        AnotherClass anotherClass = mAnotherClassReference.get();
        if (anotherClass == null) return;
        // do something with anotherClass
    }

}

AnotherClass에 대한 강력한 참조가 MyClass있습니다.

public class AnotherClass {
    
    // strong reference
    MyClass mMyClass;
    
    // allow MyClass to get a weak reference to this class
    void someMethod() {
        mMyClass = new MyClass();
        mMyClass.setWeakReference(this);
    }
}

노트

  • 참조가 약한 이유는 가비지 콜렉터가 더 이상 필요하지 않은 오브젝트를 처리 할 수 ​​있기 때문입니다. 두 객체가 서로 강한 참조를 유지하면 가비지 수집 할 수 없습니다. 메모리 누수입니다.
  • 두 객체가 서로를 참조해야하는 경우 객체 A (일반적으로 수명이 짧은 객체)는 객체 B (일반적으로 수명이 긴 객체)에 대해 약한 참조를 가져야하지만 B는 A에 대한 강한 참조를 가져야합니다. 위의 예 MyClass에서 A는 과AnotherClass B였다.
  • a를 사용하는 대안 WeakReference은 다른 클래스가 인터페이스를 구현하도록하는 것입니다. 이는 리스너 / 오브 서버 패턴 에서 수행됩니다 .

실제 예


혼란스러운 설명. 무엇 // allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }입니까 ??
likejudo

@likejudo, 당신 말이 맞아요. 변수 및 메소드 이름 중 일부를 개선했습니다. 지금 어때요?
Suragch

함수를 호출하기 전에 함수 weakreference자체에서 객체 자체 를 확인해야 합니다. doSomethingnullget
Behrouz. M

7

"정규화 된"매핑은 문제가있는 개체의 한 인스턴스를 메모리에 유지하고 다른 모든 개체는 포인터 나 이와 같은 메커니즘을 통해 특정 인스턴스를 찾는 곳입니다. 약점 참조가 도움이 될 수있는 곳입니다. 짧은 대답은 WeakReference 객체를 사용하여 시스템의 객체에 대한 포인터를 만들 수 있지만 가비지 수집기 가 범위를 벗어난 후에도 객체를 회수 할 수 있다는 것입니다. 예를 들어 다음과 같은 코드가 있다면 :

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( object );
     }
 }

에 등록 된 객체에 대한 참조가 있기 때문에 등록한 모든 객체는 GC에서 회수하지 않습니다 registeredObjects. 반면에 내가 이것을하면 :

class Registry {
     private Set registeredObjects = new HashSet();

     public void register(Object object) {
         registeredObjects.add( new WeakReference(object) );
     }
 }

그런 다음 GC가 세트의 객체를 회수하려고 할 때 그렇게 할 수 있습니다. 캐싱, 카탈로그 등을 위해이 기술을 사용할 수 있습니다. GC 및 캐싱에 대한보다 자세한 논의에 대한 참조는 아래를 참조하십시오.

참조 : 가비지 수집기 및 약한 참조

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.