Android 성능 팁

6534 단어

원문 주소


이 문서는 주로 전체 응용 성능을 향상시킬 수 있는 미세한 최적화를 덮어쓰지만 이러한 변화는 현저한 성능 효과를 가져올 수 없다.적당한 알고리즘과 데이터 구조를 선택하는 것이 항상 우선이지만, 이 문서의 범위를 넘어섰다.고효율 코드를 위해서는 이 문서의 기교를 연습으로 삼아 인코딩 습관에 심어야 한다.고효율 코드를 쓰는 데는 두 가지 기본 규칙이 있다.
  • 네가 필요로 하지 않는 일을 하지 않는다.
  • 메모리를 분배하지 않습니다. 피할 수 있다면
  • android 응용 프로그램에서 미세하게 최적화되면 가장 복잡한 문제는 응용 프로그램이 서로 다른 종류의 하드웨어에서 실행되는 것이다.VM 버전마다 프로세서마다 속도가 다릅니다.설비 X가 설비 Y보다 빠르거나 느리다고 간단하게 말할 수 없고, 한 설비와 다른 설비에서 당신의 결과를 평가할 수 없다.실제로 어떤 설비 가상 기기의 측정 결과에 대해서도 너에게 아주 적게 알려준다.JIT 설비가 있는지 없는지도 크게 다르다.JIT 설비를 휴대하는 데 가장 좋은 코드가 반드시 JIT 설비가 없는 것에 가장 좋은 코드는 아니다.당신의 응용이 서로 다른 장치에서 우수하다는 것을 확보하기 위해서는 당신의 코드가 모든 단계에서 효율적이고 당신의 성능을 극대화할 수 있도록 보장해야 한다.

    불필요한 객체 작성 방지


    대상의 창설은 결코 저렴하지 않다. 임시 대상에 대해 스레드 분배탱크가 있는 쓰레기 수집기는 분배를 저렴하게 할 수 있지만, 분배 메모리는 분배하지 않는 메모리보다 비싸다.응용 프로그램에 메모리를 너무 많이 분배하면 주기적인 쓰레기 회수를 강제로 하여 사용자 체험에 작은 트림을 일으킬 것이다.병렬 스팸 수집기는 안드로이드 2.3에 도입되었지만 불필요한 일은 피해야 한다.따라서 필요하지 않은 대상을 만드는 실례를 피해야 한다.
    도움이 될 수 있는 몇 가지 예:
    1. 문자열을 되돌려 주는 방법이 있다면, 그 결과는 항상 StringBuffer에 추가되어야 한다는 것을 알고 있다. 단명의 임시 대상을 만드는 것이 아니라, 함수를 직접 추가하는 방법을 바꾸고 서명하고 실현해야 한다.2. 입력한 데이터에서 문자열을 추출하면 복사본을 만드는 대신 원본 데이터의 하위 문자열을 되돌려 보냅니다.
    더 급진적인 생각은 다차원 그룹을 평행의 1차원 그룹으로 나누는 것이다.
    1. Integer 객체 배열보다 Int 배열이 좋고 다른 원래 유형에도 마찬가지입니다.2. 만약에 저장(Foo,Bar) 원조 대상의 용기를 실현해야 한다면 두 개의 평행수조Foo[]와Bar[]는 일반적으로 하나의 단독 사용자 정의 대상(Foo,Bar) 수조보다 낫다는 것을 기억하세요.(예외: 다른 사람이 방문하는api를 설계할 때 절충하는 것이 가장 좋다) 통속적으로 단명 임시 대상을 만들 수 있다면 피하는 것이 좋다.적은 대상 창설은 낮은 주파수의 쓰레기 수거를 의미하며 사용자 체험에 직접적인 영향을 미친다.

    Prefer Static Over Virtual


    만약 대상 필드에 접근할 필요가 없다면, 당신의 방법인 Static을 사용하십시오.집행이 일반보다 15~20% 빨라질 것이다.그것 또한 좋은 인코딩 실천이다. 왜냐하면 서명 호출 방법을 알려줄 수 있기 때문에 대상 상태의 변화를 일으키지 않기 때문이다.

    상수에 Static final 사용


    클래스 위에서 다음 선언을 사용하는 것을 고려합니다.
    static int intVal = 42;
    static String strVal = "Hello, world!";
    

    컴파일러는 클래스가 처음 사용될 때 실행하는 클래스 초기화기 방법을 생성합니다.방법은 42에서 intVal로 저장하고strVal을 클래스 파일의 문자열 상수표에서 인용합니다.이 값들이 인용되면, 그들은 검색 필드를 통해 접근합니다.저희가 이 문제를 개선할 수 있어요. "final"키워드를 통해서.
    static final int intVal = 42;
    static final String strVal = "Hello, world!";
    

    이 클래스는 정적 필드 초기화기가 dex 파일에 상수로 들어가기 때문에 더 이상 방법이 필요하지 않습니다.intVal 코드를 인용하면 42를 직접 사용합니다. 액세스 문자열은 필드 검색이 아닌 상대적으로 비싸지 않은 '문자열 상수' 명령을 사용합니다.
    주의: 이러한 최적화는 원시 형식과 문자열 상수에만 적용되며 인용 형식이 아닙니다.그리고 static final 상수는 가능한 한 좋은 인코딩 실천입니다.

    for 순환 강화 문법 사용하기


    for 순환을 강화하면 Iteratble 인터페이스의 집합과 그룹을 실현하는 데 사용될 수 있습니다.집합에서,iterator는 인터페이스hasNext () 와next를 호출하는 데 사용됩니다.Array List에서는 손으로 쓴 계수의 순환이 3배(JIT가 있든 없든) 빠르지만 다른 집합에 대해서는 for 순환 문법을 강화하는 것이 디스플레이 교체기의 사용과 같다.배열에서 선택할 수 있는 여러 시나리오를 반복합니다.
    static class Foo {
        int mSplat;
    }
    
    Foo[] mArray = ...
    
    public void zero() {
        int sum = 0;
        for (int i = 0; i < mArray.length; ++i) {
            sum += mArray[i].mSplat;
        }
    }
    
    public void one() {
        int sum = 0;
        Foo[] localArray = mArray;
        int len = localArray.length;
    
        for (int i = 0; i < len; ++i) {
            sum += localArray[i].mSplat;
        }
    }
    
    public void two() {
        int sum = 0;
        for (Foo a : mArray) {
            sum += a.mSplat;
        }
    }
    

    제로()는 가장 느리다. 왜냐하면 JIT는 순환할 때마다 array 길이의 손실을 최적화하지 못하기 때문이다.원 () 은 비교적 빠르다. 모든 물건을 로컬 변수에 저장하고, 검색을 피하며, 그룹의 길이만 성능적으로 이득을 볼 수 있다.two()는 JIT가 없는 장치에 대한 가장 빠른 속도입니다.JIT가 있는 장비는 원(one)과 크게 다르지 않다.그것은 for 순환 문법을 강화합니다.

    개인 내부 클래스는 개인 방문이 아니라 패키지 방문을 고려한다


    다음 클래스 정의를 참조하십시오.
    public class Foo {
        private class Inner {
            void stuff() {
                Foo.this.doStuff(Foo.this.mValue);
            }
        }
    
        private int mValue;
    
        public void run() {
            Inner in = new Inner();
            mValue = 27;
            in.stuff();
        }
    
        private void doStuff(int value) {
            System.out.println("Value is " + value);
        }
    }
    

    중요한 것은 우리가 개인 내부 클래스(Foo$Inner)를 외부 클래스에 직접 접근하는 방법과 개인 실례 필드를 정의하는 것이다. 이것은 합법적이다. 기한 코드로'Value is 27'을 출력하는 것은 VM이 직접 Foo's에 접근하는 개인 구성원이Foo$Inner에서 비합법적이라고 생각하는 것이다. 왜냐하면Foo와Foo$Inner는 서로 다른 클래스이기 때문이다. 자바 언어가 내부 클래스가 외부 클래스에 직접 접근하는 개인 구성원을 허용하더라도,격차를 메우기 위해 컴파일러는 한 쌍의 합성 방법을 생성한다.
    /*package*/ static int Foo.access$100(Foo foo) {
        return foo.mValue;
    }
    /*package*/ static void Foo.access$200(Foo foo, int value) {
        foo.doStuff(value);
    }
    

    내부 클래스 코드는 mValue 필드에 액세스하거나 외부 클래스에서 DoStuff () 방법을 호출할 때마다 이러한 정적 방법을 호출합니다.이것은 위의 코드가 액세스 구성원 변수로 변하여 액세스기를 통과한다는 것을 의미한다.이전에 우리는 방문기가 직접 방문 필드보다 느리다고 토론한 적이 있기 때문에 이것은 '보이지 않는' 성능에 영향을 주는 예이다.만약 성능 핫이슈에서 이러한 코드를 사용한다면, 성명 필드와 방법을 통해 내부 클래스에 패키지로 접근해서 손실을 피할 수 있다.개인 방문이 아니라불행하게도 이 필드는 같은 가방의 다른 클래스에 직접 접근할 수 있기 때문에 공공 Api에서 이렇게 사용해서는 안 된다.

    부동 소수점 사용 방지


    일반적으로 부동점수는 정형보다 두 배 느리고 안드로이드를 지원하는 장치에 있다.속도 면에서 플로트와 더블은 다수의 현대 설비에서 구별되지 않는다.공간적으로는 더블이 두 배나 크다.대부분의 데스크톱에서, 만약 공간이 문제가 아니라면,float가 아닌 더블을 선택해야 한다.또한 정형에 대해 일부 프로세서에는 하드웨어 곱셈기가 있지만 하드웨어 제법기가 부족하여 정형 상제와 계수 조작이 소프트웨어에서 실행된다. - 만약hash표를 설계하거나 수학 연산을 많이 하고 있을 때 고려해야 한다.

    라이브러리 이해 및 사용


    흔히 볼 수 있는 원인을 제외하고 자신의 코드가 아닌 라이브러리를 선택하고 시스템이 수동으로 작성한 어셈블러로 호출하는 라이브러리 방법을 자유롭게 기억하는 것은 JIT가 생성한 것보다 같은 자바 코드에 대해 더 효율적이다.전형적인 예는 스트링이다.indexOf() 및 관련 API.비슷한, 시스템.arraycopd () 방법은 손으로 쓰는 순환의 9배가 JIT가 있는 넥서스 장치에 있다.

    조심스럽게 로컬 방법을 사용하다


    응용 프로그램을 개발할 때 안드로이드 NDK를 사용하는 것이 자바 코드를 사용하는 것보다 반드시 효율적인 것은 아니다.Java-native 전환과 관련이 있을 때 손실이 있기 때문이다.또한 JIT는 이러한 경계를 뛰어넘어 최적화할 수 없다.만약 로컬 자원 (로컬 더미의 메모리, 파일 설명자, 또는 기타) 을 분배한다면, 이 자원의 집합을 실시간으로 분배하는 것보다 훨씬 어렵다.너도 모든 지원하는 구조에 대한 코드를 컴파일해야 한다. (JIT에 의존하는 것이 아니라.)ARM in G1 프로세서를 위해 컴파일된native 코드는 ARM in Nexus One에 충분히 활용되지 않으며 ARM in Nexus One에 컴파일된 코드는 ARM in G1에서 실행되지 않습니다.Native code는 현존하는 로컬 코드가 있으면 안드로이드에 이식하기를 원하지, 안드로이드에서 자바로 쓴 부분의 기능을 가속화시키지 않는 역할을 한다.native code를 사용하려면 JNI Tips를 읽어야 합니다.

    성능 오류


    JIT가 없는 장치에서 호출 방법은 인터페이스가 아니라 정확한 유형을 가진 방법을 통해 효율적으로 작동하는 것이 사실이다.(예를 들어 HashMap 맵에 호출하는 방법은 Map 맵보다 경량급이다. 두 맵이 모두 HashMap일지라도) 이것은 두 배 느리지 않고 실제적인 차이는%6이다.또한 JIT는 양자에 뚜렷한 차이가 없다. JIT가 없는 장치에서 캐시 필드 접근은 한 필드에 반복 접근하는 것보다%20이 빠르다.JIT가 있고 필드 접근 소모와 로컬 접근 차이가 많지 않기 때문에 코드를 쉽게 읽을 수 있도록 최적화할 가치가 없습니다.(final,static,static final 필드도 마찬가지)

    Always Measure


    최적화를 시작하기 전에 문제가 있는지 확인하고 현재의 성능을 정확하게 측정할 수 있도록 하세요. 그렇지 않으면 교체 방안의 장점을 측정할 수 없습니다.Traceview가 성능 분석에 도움이 된다는 것을 발견할 수 있지만, 현재 JIT를 사용하지 않는 것이 더 중요하다는 것을 깨닫게 될 것이다.Traceview를 실행하지 않을 때 Traceview의 제안 데이터에 따라 변경된 후에 결과 코드가 실제적으로 더 빨리 실행될 수 있도록 하는 것이 중요하다.더 많은 도움말과 응용 프로그램을 디버깅하려면 다음 문서를 참조하십시오: • with Traceview and dmtracedump • Analyzing UI Performance with Systrace

    좋은 웹페이지 즐겨찾기