ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 아이템6. 불필요한 객체 생성을 피하라
    Java/이펙티브 자바 2022. 11. 10. 17:39

    핵심정리

    - 문자열

        ㆍ사실상 동일한 객체라서 매번 새로 만들 필요가 없다

        ㆍnew String("자바") 을 사용하지 않고 문자열 리터럴("자바")을 사용해 기존에 동일한 문자열을 재사용하는 것이 좋다

             ○ JVM 은 pool에서 캐싱하고 있기에 new String을 한다면 강제적으로 새로운 문자열을 만드는 것이다.

    public class Strings {
        public static void main(String[] args) {
            String hello = "hello";
    
            // 이 방법 권장 X
            String hello2 = new String("hello");
            String hello3 = "hello";
    
            System.out.println(hello == hello2);        // false
            System.out.println(hello.equals(hello2));   // true
            System.out.println(hello == hello3);        // true
            System.out.println(hello.equals(hello3));   // true
    
        }
    }

    - 정규식, Pattern

        ㆍ생성 비용이 비싼 객체라서 반복해서 생성하기 보다, 캐싱하여 재사용하는 것이 좋다.

    // 값비싼 객체를 재사용해 성능을 개선한다. (32쪽)
    public class RomanNumerals {
    
        // 코드 6-1 성능을 훨씬 더 끌어올릴 수 있다!
        static boolean isRomanNumeralSlow(String s) {
            return s.matches("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
        }
    
        // 코드 6-2 값비싼 객체를 재사용해 성능을 개선한다.
        private static final Pattern ROMAN = Pattern.compile("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
    
        static boolean isRomanNumeralFast(String s) { return ROMAN.matcher(s).matches(); }
    
        public static void main(String[] args) {
            boolean result = false;
            long start = System.nanoTime();
            for (int j = 0; j < 100; j++) {
                // 성능 차이를 확인할려면 Slow -> Fast 메서드 변경
                result = isRomanNumeralSlow("MCMLXXVI");
            }
            long end = System.nanoTime();
            System.out.println(end - start);
            System.out.println(result);
        }
    }

    - 오토박싱(auto boxing)

        ㆍ기본 타입(int)을 그게 상응하는 박싱된 기본 타입(Integer)으로 상호 변환해주는 기술.

        ㆍprimitive -> wrapper : auto boxing / wrapper -> primitive : unboxing

        ㆍ기본 타입과 박싱된 기본 타입을 섞어서 사용하면 변환하는 과정에서 불필요한 객체가 생성될 수 있다.

    public class Sum {
        private static long sum() {
            Long sum = 0L;	// 6초
            long sum = 0L;	// 1초
            for (long i = 0; i <= Integer.MAX_VALUE; i++) {
                sum += i;
            }
            return sum;
        }
    
        public static void main(String[] args) {
            long start = System.nanoTime();
            long x = sum();
            long end = System.nanoTime();
            System.out.println((end - start) / 1_000_000. + " ms.");
            System.out.println(x);
        }
    }

    - "객체 생성은 비싸니 피하라."는 뜻으로 오해하면 안된다.


    완벽 공략

    - p31, 사용 자제 API(Deprecation)

    - p32, 정규 표현식

    - p32, 한 번 쓰고 버려져서 가비지 컬렉션 대상이 된다.

    - p33, 초기화 지연 기법(아이템 83에서 다룸)

        ㆍ진짜 가끔 사용되는 필드에 사용

    - p34, 방어적 복사(아이템 50에서 다룸)

        ㆍ새로운 객체를 만들때 기존 객체를 복사해서 만들지 마라

    완벽 공략 16 - Deprecation

    : 클라이언트가 사용하지 않길 바라는 코드가 있다면...

    - 사용 자제를 권장하고 대안을 제시하는 방법이 있다.

    - @Deprecated

        ㆍ컴파일시 경고 메시지를 통해 사용 자제를 권장하는 API라는 것을 클라이언트에 알려줄 수 있다.

    - @deprecated

        ㆍ문서화(Javadoc)에 사용해, 왜 해당 API 사용을 지양하며, 그 대신 권장하는 API가 어떤 것인지 표기할 수 있다.

    public class Deprecation {
    
        /**
         * @deprecated in favor of
         * {@link #Deprecation(String)}
         */
        @Deprecated(forRemoval = true, since = "1.2")
        public Deprecation() {
    
        }
    
        private String name;
    
        public Deprecation(String name) {
            this.name = name;
        }
    }

     

    완벽 공략 17 - 정규 표현식

    : 내부적으로 Pattern이 쓰이는 곳

    - String.match(String regex)

    - String.split(String regex)

        ㆍ대안, Pattern.compile(regex).split(str)

    - String.replace*(String regex, String replacement)

        ㆍ대안, Pattencompile(regex).matcher(str).replaceAll(repl)

    - 과제) 자바 정규식 Pattern 문법 학습하기

    - 참고 1) https://docs.oracle.com/javase/tutorial/essential/regex 

    - 참고 2) https://regex101.com 또는 https://regexr.com/ 

     

    - split의 one-char String 는 빠르다. 컴파일하지 않아도 빠르게 처리된다.

    - split도 여러 char를 가지고 할 때는 pattern을 미리 만드는 것이 좋다.

    public class RegularExpression {
        private static final Pattern SPLIT_PATTERN = Pattern.compile(",");
    
        public static void main(String[] args) {
            long start = System.nanoTime();
            for (int j = 0; j < 10000; j++) {
                String name = "keesun,whiteship";
                name.split(",");
    //            SPLIT_PATTERN.split(name);
            }
            System.out.println(System.nanoTime() - start);
        }
    }
    
    // match, split, replaceAll, replaceFirst

     

    완벽 공략 18 - 가비지 컬렉션

    - Mark, Sweep, Compact

        ㆍMark : 오브젝트가 참조를 가지고 있는지 없는지 체크, 사라져도 되는 인스턴스인지 체크

        ㆍSweep : 필요없는 오브젝트를 메모리 힙에서 날리는 것

        ㆍCompact : 중간에 비워져있는 오브젝트 파편들을 없애고 모아주는 과정

     

    - Young Generation (Eden, S0, S1), Old Generation

        ㆍYoung Generation : 금방 사라지는 객체들을 관리

        ㆍOld Generation : 오래 살아남는 객체들을 관리

     

    - Minor GC, Full GC

        ㆍMinor GC : Young Generation에서 일어나는 GC

        ㆍFull GC : Young Generation과 Old Generation 동시에 일어나는 GC

     

    - Throughput, Latency (Stop-The-World), Footprint - 3가지 관점에서 GC 종류들을 봐야한다.

        ㆍThroughput : 애플리케이션 처리양, 내 서버의 리소스를 얼마만큼 사용하는가?

        ㆍLatency : GC의 Compact하는 과정에 멈춤, 즉, GC만 일을 한다. GC를 하는 동안에는 요청처리가 되지 않는다.

                           Serial과 Parallel은 Latency 관점에서는 좋은 GC는 아니다.

        ㆍFootprint : GC 알고리즘을 수행함으로써 얼마나 많은 메모리 공간을 필요로 하는가?

    * 3가지 중 Latency가 가장 중요하다. 응답시간에 영향을 끼칠 수 있기 때문에..가장 짧은 Latency를 선택

     

    - Serial, Parallel, CMS, G1, ZGC, Shenandoah

        ㆍSerial 

        ㆍParallel : 자바8의 기본 GC, Serial GC에 비해 스레드를 더 쓰는 것

        ㆍCMS : 자바9부터 deprecated가 됨, 13/14부터는 사라짐

        ㆍG1 : 자바11의 기본 GC

        ㆍZGC

        ㆍShenandoah

     

    - 참고) How to choose the best Java garbage collection?

     

     

    가비지 컬렉션을 알기 위한 것들

    1. 가비지 컬렉션 기본 개념

    2. Optional

    3. tools

    댓글

Designed by Tistory.