매일 한 개의 면접문제(제3기)---일반적으로 어떤 상황에서 메모리 유출 문제를 초래할 수 있습니까

6497 단어
자질구레한 것들은 늘 오래 기억하지 못하고, 남의 문장만 배워도 남이 씹어 남긴 잔재일 뿐이다.무심결에 이 매일 한 개의 면접 문제를 발견했다. 만약에 간단하게 생각하기만 한다면 효과가 적을 뿐만 아니라 어려운 문제도 스스로 생각하기 귀찮아서 견딜 수 없을 것이다.그래서 매번의 사고, 이해와 다른 사람의 견해를 기록하는 것이 낫다.자신의 이해를 깊이 있게 할 뿐만 아니라, 더욱 자신을 견지하도록 격려해야 한다.

메모리 누설


정의


방출되거나 쓸모없어야 할 대상은 다른 생존 대상이 인용을 가지고 있기 때문에 이 대상은 쓰레기 수거기에서 회수되지 못하고 메모리를 계속 차지하여 프로그램 실행을 느리게 하거나 붕괴시킨다.

까닭


왜 다른 생존 대상에게 인용을 가지고 있으면 회수할 수 없습니까?이것은 자바의 쓰레기 회수 메커니즘을 이해해야 한다.
java 쓰레기 회수 메커니즘
어떤 대상이 회수해야 한다고 여겨질까요?우리는 현재 모든 대상을 지향도의 결점으로 간주하고, 대상 간의 인용 관계는 지향도의 변이 있다.그러면 반드시 시작 결점 대상이 있을 것이다. 만약 이 대상이
  • 방법구의 클래스 정적 속성 인용 대상
  • 방법구의 상수 인용 대상
  • 로컬 방법 창고의native 방법 인용 대상
  • 가상 머신 창고(창고 프레임의 로컬 변수 테이블(국부 변수 테이블))에서 인용된 대상
  • 그러면 이 대상은 그림에 옮겨다니는 모든 대상에게 회수되지 않는다.반대로 회수할 대상으로 여겨진다.
    추상적으로 말하자면, 한 프로그램에 이런 유방향도가 많이 존재할 것이다. 만약에 한 대상이 두 개의 시작 결점 대상이 존재하는 유방향도에 인용된다면.하나의 유방향도가 사명을 완수하려면 소각되어야 하지만, 다른 유방향도의 생명주기는 아직 끝나지 않았다.그러면 이 쓸모없어야 할 대상은 쓰레기 수거기에서 회수할 수 없고 다른 지향도 생명주기가 끝나야만 회수될 수 있다.
    따라서 우리가 흔히 말하는 생명주기가 다른 두 대상 사이에 인용 관계가 있고 생명주기가 짧으면 메모리 유출을 초래할 수 있으며 지속 시간은 생명주기가 긴 대상에 달려 있다.만약 이 대상이 정적 변수라면, 프로그램 전체가 끝날 때까지 지속될 것입니다.

    안드로이드 메모리 누출 상황


    집합류


    일반적인 집합 클래스는 메모리 유출을 일으키지 않지만 전체적인 집합 클래스라면 사용이 끝난 후remove 작업을 주의하지 않으면 메모리 유출을 초래할 수 있습니다.

    단일 모드


    여기서 단일 예제 모드는 만들 때 매개 변수로 Context를 입력해야 한다는 것을 말합니다.예를 들어 우리가 자주 쓰는 아래의 이 코드.
    public class Manager {
        private static Manager instance;
        private Context context;
        private Manager(Context context){
            this.context = context;
        }
    
        public static Manager getInstance(Context context){
            if(instance == null){
                instance = new Manager(context);
            }
            return instance;
        }
    }
    

    관건은 이 Context에 있다. 만약에 이 Context가Activity의 Content라면 Activity의 생명주기와 단일 모드의 대상의 생명주기가 다르다는 것이 분명하다. Content에 전송된Activity가 사용되고 회수되어야 할 때 쓰레기 수거기에서 회수할 수 없다.
    이 Context가 Application일 때 메모리 유출 문제가 존재하지 않는다는 것은 명백하다.단일 모드의 대상과 Application의 생명주기는 전체 응용의 생명주기이기 때문에 아무런 문제가 없다.
    그래서 우리는 이렇게 쓸 수 있다
    public class Manager {
        private static Manager instance;
        private Context context;
        private Manager(Context context){
            this.context = context.getApplicationContext();
        }
    
        public static Manager getInstance(Context context){
            if(instance == null){
                instance = new Manager(context);
            }
            return instance;
        }
    }
    

    물론 Application의 Context도 마음대로 사용할 수 있는 것은 아니다.Activity를 시작하려면 Application에서 새 Task 작업 스택을 만들어야 합니다.Dialog를 만들려면Activity의 context만 가능합니다.

    익명 내부 클래스


    익명 내부 클래스에 대해 안드로이드에서 전형적인 예는 핸들러죠.이것은 내가 1기에서 사용자 정의Handler가 메모리 유출을 어떻게 효과적으로 보장하는지 이미 분명하게 말했다.주로 익명 내부 클래스가 외부 클래스의 인용을 가지고 있기 때문에 익명 내부 클래스의 일부 조작으로 인해 이 내부 클래스 대상의 생명 주기와 외부 클래스의 생명 주기가 같지 않아 메모리 유출을 초래한다.

    비정상 내부 클래스


    개발 과정에서 우리는 프로그램의 효율과 자원의 중복 이용을 위해 이런 코드를 자주 쓸 수 있다.
    public class MainActivity extends BaseActivity {
        private static Resource resource = null;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if(resource == null){
                resource = new Resource();
            }
        }
    
        class Resource{
        }
    }
    

    이렇게 하면 자원의 중복 생성을 효과적으로 피할 수 있지만Activity가 시작될 때마다 이 자원을 신속하게 사용하지만 메모리 유출을 초래할 수 있다.비정상적인 내부 클래스도 기본적으로 외부 클래스의 인용을 가지고 있기 때문이다.이 비정상적인 내부 클래스의 정적 실례는 전체 응용 프로그램과 생명주기가 똑같이 길기 때문에 메모리 유출을 초래할 수 있다.
    해결 방법은 이 내부 클래스를 정적 내부 클래스로 설정하거나 이 내부 클래스를 추출하여 하나의 단일 모델로 봉인하는 것이다.

    자원이 닫히지 않았습니다.


    Broadcast Receiver, File, Course,Stream,Content Observer 등 자원을 사용하거나 일부 프레임워크 이벤트bus 등에서 Register와 unRegister가 필요하다고 명확하게 표시할 때,Activity가 소각될 때 닫거나 취소해야 한다. 그렇지 않으면 이 자원들은 회수되지 않을 것이다.

    불량 코드로 인한 압력


    때때로 제때에 회수하지 못한 대상이 초래한 메모리 유출이 아니라 일부 코드가 필요하지 않은 메모리를 제때에 효과적으로 방출하지 않거나 기존 자원을 효과적으로 이용하지 못해 빈번하게 새로운 메모리를 신청하지 않아 메모리에 큰 압력을 가한다.
    예를 들어ListView의ContentView는 ViewHolder의 유효한 복용 View를 사용하지 않고 빈번하게 새로운 View를 만들어서 메모리 압력을 발생시킨다.

    좋은 웹페이지 즐겨찾기