읽기 전

  • 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
  • 개인적으로 사용해보면서 배운 점을 정리한 글입니다.

문제 제기

변수 저장에 대해 물어보면 으레 지역/매개 변수는 스택, 기본 자료형은 선언된 위치에 의존, 참조 자료형은 reference만 선언된 위치에 의존하고 실제 객체는 힙에 저장된다고 말한다. 그런데 기본과 참조 자료형으로 나뉘는 변수에 대해서도 클래스, 인스턴스, 지역/매개 변수로 나뉘는데 이에 대해 구분해서 명확하게 알아둘 필요가 있어보여 정리하기로 했다.

주의점

변수(variable)가 (변수, 값)으로 구성되었다고 생각하면 혼동하기 쉽다. 엄연히 변수는 변수에 할당된 값을 가리키는 reference이고 변수에 할당된 값은 별개의 개념이라 생각하자.

public class Test {
    static int classPrim = 10;
    static String classRefer = new String("Variable");
    static String classLiter = "Variable";
    int instancePrim = 100;
    String instanceRefer = new String("Variable");
    String instanceLiter = "Variable";

    public static void main(String[] args) {
        Test test = new Test();
    }

    public void methodTest(int paramPrim, String paramRefer) {
        int innerPrim = 10;
        String innerRefer = new String("Variable");
        String innerLiter = "Variable";
    }
}

지역/매개변수 위치

지역/매개변수 - 기본 자료형

메소드 내에 생성되거나 전달된 지역/매개변수에 할당된 값이 기본자료형(정수, 소수, boolean)일 경우 stack에 저장된다고 보면 된다. 메소드가 종료되면 그대로 소멸한다.

지역/매개변수 - 참조 자료형

메소드 내에 생성되거나 전달된 변수에 참조 자료형(배열, 클래스 객체 등 new 연산자로 생성)이 할당될 경우 할당된 실제 객체는 heap에 저장되고 heap에 저장된 객체를 가르키는 reference가 stack에 저장된다. 역시나 메소드가 종료되면 객체에 생성되었던 데이터를 향한 heap 주소 reference가 삭제되고 연결이 끊긴 객체를 GC가 적당히 소멸시킨다.

인스턴스 변수 위치 - 기본/참조 자료형

인스턴스 변수는 클래스를 기반으로 생성된 객체의 부분이므로 참조 자료형(객체) 내에 포함된 것으로 간주할 수 있다. 따라서 메소드 바깥에 선언된 static하지 않은 변수의 값들은 모두 생성된 객체를 따라 heap에 저장되고 인스턴스를 생성하고 호출하는 위치가 메소드 내부이므로 reference가 stack에 저장된다. 인스턴스 변수는 GC에 의해 객체가 소멸될 때까지 heap에 위치한다.

클래스 변수 위치

메소드 바깥에 선언되며 static한 변수를 클래스 변수라 한다. 클래스에 대한 객체를 생성하지 않고도 접근할 수 있는데 저장 위치에 대해 해외 포럼에서도 용어가 혼재되어 있다.

클래스 변수는 heap에서 "logical"하게 구분된 Permanent의 Method 영역에 저장된다. 정확히는 runtime constant pool에 존재한다. runtime constant pool에는 class meta data와 특이하게 numeric constant value, string constant value(interned strings)가 저장된다.

클래스 변수 - 기본 자료형

클래스 변수에 기본 자료형을 할당하면 runtime constant pool에 class meta data로 변수가 저장되고 변수에 할당된 값이 numeric constant value로 저장된다.

클래스 변수 - 참조 자료형

기본 자료형과 스트링을 제외한 참조 자료형(객체, 배열 등)인 경우 클래스 변수에 할당된 객체는 heap에 생성해두고 reference를 runtime constant pool에 저장한다.

String Literal

new 연산자로 생성하는 참조 자료형과는 달리 String은 Literal 형태로 변수에 값을 할당할 수 있다.(ex. String buf = "buf";) 그리고 이 값은 runtime constant pool의 string constant value에 저장되는데 참조 자료형임에도 heap에 생성하지 않았던 이유는 Java 초기 개발진은 String 객체는 자주 재사용될 여지가 있다 판단하여 heap과는 별개로 데이터를 저장하였다. 이러한 이유로 메소드 내에서든 객체 변수로든 클래스 변수로든 동일한 literal string이라면 동일한 주소를 가르키게 되었다. 이는 "==" 연산으로 확인할 수 있다.

요약

Java 7

Development_Java_store_variable_object_001.png

Permanent Generation이 존재했을 시기엔 변수의 위치와 할당된 값이 위 그림처럼 배치될 거라 이해했다.

Java 8

Development_Java_store_variable_object_001.png

Java 8에서는 Permanent Generation이 삭제되고 Metaspace로 대체되면서 Metaspace는 class meta data만을 관리하고 클래스 변수의 리터럴 값을 저장하던 runtime constant pool의 numeric constants와 string constants가 heap 영역으로 이관되어 GC 대상에 적용되었다. 그 내용을 표현하면 위 그림처럼 배치될 것이다.

읽기 전

  • 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
  • 개인적으로 사용해보면서 배운 점을 정리한 글입니다.

문제 제기

변수 저장에 대해 찾아보다 보면 constant pool이라던지 stack이라던지 heap이라던지 용어가 많이 나오는데 constant pool은 method 영역에 속하지만 그 메소드 영역은 어디에 위치하는지 등 diagram으로 그린 글이 몇 없어 이번 기회에 정리해보려 한다. 런타임 데이터 영역에 대해 확실히 정리한 뒤 클래스/인스턴스 변수, 기본/참조 자료형의 저장 위치에 대해 정리해보려 한다.

결정적으로 runtime constant pool과 string constant pool의 개념을 서로 분리해서 설명하는 종자들 때문에 이 포스팅을 작성하게 되었다.

자바 메모리 - Runtime Data Area

런타임 데이터 영역(Runtime Data)은 실제 클래스 파일이 적재되는 곳으로 JVM이 OS로부터 자바 프로그램 실행을 위한 데이터와 명령어를 저장하기 위해 할당받는 메모리 공간이다. 주로 메소드, 힙, 스택 영역을 언급한다.

Development_Java_runtime_data_area_001.png

일반적으로 Runtime Data Area를 정리하면 위의 그림대로 설명하는 편이다.

  • 메소드(=클래스=스태틱) 영역
    • 가장 먼저 데이터가 저장됨
    • 클래스 로더에 의해 로드된 클래스, 메소드 정보와 클래스 변수 정보 저장
    • 클래스 변수 남발 시 메모리 공간 부족할 수 있음
      • Java 7의 경우 부족할 수 있었으나 Java 8부터는 개선됨
    • 프로그램 시작부터 종료될 때까지 메모리에 적재
    • 명시적 null 선언 시 GC가 청소
    • 모든 스레드가 공유함
  • 힙 영역
    • 런타임 시 결정되는 참조 자료형이 저장됨
      • 런타임 시 결정됨에 따라 동작 중의 문제(범위 초과 참조 등)가 발생할 코드임에도 문법의 문제는 아니기에 컴파일 시 에러를 출력하지 않음
    • new 연산자를 통해 생성된 객체(인스턴스)가 저장되는 공간
      • 즉, 인스턴스 변수도 여기에 저장됨
    • 객체가 더 이상 쓰이지 않거나 명시적 null 선언 시 GC가 청소
    • 모든 스레드가 공유함
  • 스택
    • 컴파일 시 결정되는 기본 자료형(&참조변수)이 저장됨
      • 컴파일 시 결정됨에 따라 자료형의 범위를 초과한 값 할당 등의 코드가 컴파일 단계에서 검출됨
      • 참조 변수는 기본 자료형을 Wrapper Class로 boxing한 변수(Integer, Byte 등)
    • 메소드 호출 시 메모리에 FILO로 삽입
    • 메소드 종료 시 메모리에서 LIFO로 제거
    • 메소드가 호출될 때마다 각각의 스택 프레임이 생성됨
      • 각 스택 프레임은 하나의 메소드에 대한 정보를 저장
    • {} 혹은 메소드가 종료될 때 삭제됨
      • 메소드 종료 시 프레임 별로 삭제
    • 각 스레드 별로 생성
  • PC 레지스터
    • JVM이 수행할 명령어의 주소를 저장하는공간
      • OS의 PC 레지스터와 유사한 역할이나 CPU와는 별개로 JVM이 관리
    • 스레드가 시작될 때마다 생성됨
    • 각 스레드 별로 생성
  • 네이티브 메소드 스택
    • 바이트 코드가 아닌 기계어로 작성된 코드를 실행하는 공간
    • 다른 언어(c/c++)로 작성된 코드를 수행하기 위함
    • Java Native Interface를 통해 바이트 코드로 변환됨
    • Java Code를 수행하다 JNI 호출 시 Java Stack에서 Native Stack으로 동적 연결(Dynamic Linking)을 통해 확장됨
      • 따라서 나뉘어졌다고는 하나 stack에서 연결할 수 있음
    • JNI(Java Native Interface) 호출 시 생성
    • 각 스레드 별로 생성

Runtime Data Area의 구분

그런데 변수 저장에 대해 공부하다 보면 위의 내용에 따라 클래스 변수는 Method Area에 저장된다는데 오라클 문서에 따르면 logical하게는 heap에 속한다 설명한다. 뭔가 아예 별개로 설명하자니 애매하다. 이에 대해 대부분의 글들은 별다른 설명 없이 넘어가곤 한다. 엄밀하게 각 영역별로 어떻게 구성되는 지 따져보고자 한다. 크게 저장 공간에 따라 heap과 stack으로 구성되고 그 내부에 다른 영역이 포함된다고 간주하면 되겠다.

Heap 영역? Method 영역?

Development_Java_runtime_data_area_002.png

위 그림이 일반적으로 jvm의 heap 구조를 설명할 때 사용하는 그림이다. 그런데 permanent 영역은 보통 heap취급을 하지 않지만 이렇게 heap 영역에 "포함된" 상태다. 그런데 일반적으로 permanent 영역과 heap 영역은 구분해서 설명한다. 그리고 Method 영역은 permanent 영역에 속해있어 heap 영역이 아니라고 보통 이야기한다. 따라서, heap 영역에 포함되어 있기는 하나 heap 영역과는 구분해서 간주함으로 인해 오라클 문서에서 logical하게는 heap의 한 부분이라고 설명하는 것이다.

Heap의 Permanent Generation영역 변화

  • Java 7 JVM
<----- Java Heap -----------------> <--- Native Memory --->
+------+----+----+-----+-----------+--------+--------------+
| Eden | S0 | S1 | Old | Permanent | C Heap | Thread Stack |
+------+----+----+-----+-----------+--------+--------------+
                        <--------->
                       Permanent Heap
S0: Survivor 0
S1: Survivor 1
  • Java 8 JVM
<----- Java Heap -----> <--------- Native Memory --------->
+------+----+----+-----+-----------+--------+--------------+
| Eden | S0 | S1 | Old | Metaspace | C Heap | Thread Stack |
+------+----+----+-----+-----------+--------+--------------+

Permanent 영역은 JVM에 의해 크기가 제한된 영역으로 Java 7까지 유지되었다. 따라서 영역 제한으로 인해 메모리 범위 초과 문제가 있었다. 대신 Java 8부터는 Permanent Generation을 제거하고 Metaspace로 대체하였고 heap이 아니라 JVM에 의해 메모리가 제한되지 않는 Native Memory 영역으로 전환하여 OS에 의해 메모리 할당 공간이 자동으로 조절되므로 이론상 아키텍쳐가 지원하는 메모리 크기까지 확장할 수 있다.

따라서, 애매하게 heap에 걸쳐있던 permanent 영역이 non-heap이라고 구분하던 과거와는 달리 명확하게 method area는 heap이 아니라고 정의할 수 있게 되었다.

변경 이유는 ArrayList와 같은 레퍼런스 타입의 동적 배열 객체를 static으로 생성하면 레퍼런스를 Permanent 영역에 저장하는데 해당 객체 배열에 객체 원소를 추가하면 그대로 static object의 레퍼런스가 Permanent 영역에 쌓일 뿐만 아니라 string literal data를 저장하던 string pool도 permanent 영역에 저장하느라 OOM 에러가 발생하는 이슈가 잦았다고 한다.

Permanent에서 Metaspace로 변경됨에 따른 변화

오라클 문서에 The proposed implementation will allocate class meta-data in native memory and move interned Strings and class statics to the Java heap. Hotspot will explicitly allocate and free the native memory for the class meta-data.라고 나와있다. 해석하자면 class meta-data는 native memory로 이동된 Metaspace에 저장하고 permanent에 저장했던 interned strings와 static 변수는 heap 영역으로 보낸다는 의미가 된다. Java8부터는 static 변수를 heap영역에서 관리함은 gc 대상이 될 수 있음을 의미한다. 으레 다들 설명하듯 PermGen에 속한 Method area가 클래스 변수를 저장한다고 알고 있다면 이해하기 쉽지 않다. static 변수는 클래스 변수로 명시적 null 선언이 되지 않으면 gc되어서는 안되는 변수다. Method area가 클래스 변수를 저장한다고 이해하는 시점에서 오해가 발생한다 Method area는 class의 meat-data를 저장할 뿐 실질적인 객체와 데이터는 Method area 바깥의 PermGen에 저장됨을 알아야 한다.

class meta-data가 metaspace로 이동하고 기존에 perment 영역에 저장되던 static object는 heap영역에 저장되도록 변경되었다고 설명하는데 이는 reference는 여전히 metaspace에서 관리됨을 의미하기에 참조를 잃은 static object는 GC의 대상이 될 수 있으나 reference가 살아있다면 GC의 대상이 되지 않음을 의미한다.

따라서, metaspace는 여전히 static object에 대한 reference를 보관하며 애매하게 heap에 걸쳐지지 않고 non-heap(native memory)로 이관되며 static 변수(primitive type, interned string)는 heap 영역으로 옮겨짐에 따라 GC의 대상이 될 수 있게끔 조치한 것이다.

이 내용을 언급하는 이유는 클래스 변수 및 객체의 저장위치와 클래스 메타 정보의 위치가 Method 영역이 속한 ParmGen으로부터 Heap과 메모리로 서로 분리되었다는 점을 의미하기 때문이다.

Stack 영역

Development_Java_runtime_data_area_003.png

PC 레지스터와 스택, Native Method 스택은 각 스레드마다 생성된다고 설명했다. 그리고 스택에는 메소드 호출마다 프레임이 생성되어 쌓이며 프레임에는 리턴할 값, 지역 변수, 연산자 스택, 현재 클래스 constant pool의 값을 호출할 레퍼런스가 있다. 이 레퍼런스를 통해 클래스, 인스턴스 변수들이나 생성된 참조 자료형을 호출한다.

읽기 전

  • 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
  • 개인적으로 사용해보면서 배운 점을 정리한 글입니다.

문제 제기

Java는 JVM이라는 가상 머신을 통해 OS 종류와는 관계 없이 구동 환경만 적합하면 코드를 실행할 수 있다. 따라서 Java의 특징적인 컴파일 환경, JVM의 구조 등을 정리하려 한다.

해당 파트는 java 소스코드 작성 후 컴파일 프로세스와 jvm에 바이트 코드 실행 시 내부 데이터를 저장 및 관리하는 흐름에 대한 내용이다.

컴파일 흐름 및 자바 가상 머신의 구성

Development_Java_compile_runtime_environment_001.png

  1. 개발자가 자바 소스 코드(.java)를 작성
  2. 자바 컴파일러(javac)가 자바 소스 코드파일 컴파일 수행
    • 자바 바이트코드(.class) 파일 생성
    • OS는 non-Readable, JVM은 Readable
    • 바이트 코드의 명령어는 1바이트 크기의 opcode와 추가 피연산자로 구성
  3. 컴파일된 바이트 코드를 JVM의 클래스 로더에 전달
  4. 클래스 로더가 클래스 파일을 JVM 내부로 로딩, 파일을 분석하여 런테임 데이터 영역에 배치
    • 동적 로딩을 수행하므로 런타임 시점이 되어야 모든 코드가 JVM과 링크됨
    • 클래스 로더 세부 동작
      • 로드 : 바이트 코드 파일을 가져와서 JVM 메모리에 적재
      • 검증 : 자바 언어 및 JVM 명세에 명시된 대로 구성되어 있는지 검사
      • 준비 : 클래스가 필요로 하는 메모리 할당 (필드, 메소드, 인터페이스 등)
      • 분석 : 클래스의 Constatnt Pool 내에 저장된 모든 Symbolic Reference를 Direct Reference로 변경
      • 초기화 : 클래스 변수를 적절한 값으로 초기화(static)
  5. 실행 엔진(Execution Engine)은 JVM 메모리에 적재된 바이트 코드들을 명령어 단위로 하나씩 가져와서 실행함, 실행 방식은 두 가지로 나뉨
    • 인터프리터 : 바이트 코드 명령어를 하나씩 읽고 해석하고 실행, 명령어 실행 단위 시간은 빠르나 전체적인 실행 속도는 느림
    • JIT(Just-In-Time) 컴파일러 : 인터프리터의 단점을 보완하기 위해 도입되었으며 바이트 코드 전체를 컴파일하여 기계어로 변경한 후 해당 메소드를 더 이상 인터프리팅하지 않고 바이너리 코드로 직접 실행, 전체 실행 속도는 빠르나 초기 변환 비용이 발생
  • 가비지 컬렉터(Grabage Collector)
    1. 참조되지 않는 객체들을 탐색 후 삭제
    2. 삭제된 객체의 메모리 반환
    3. 힙 메모리 공간 확보(다른 공간의 경우도 확보할 경우 있긴 함)

좀 특이한 규칙의 코딩테스트였다. 휴대폰 카메라로 실황을 중계하며 화면공유는 하되 검색은 허용되는 코딩테스트라니 네이버의 환경과 카카오의 규칙을 섞은 기분이다. 덕분에 난이도는 조금 너프되었다고 생각한다. 결과는 올솔.

1번은 문자열 다루기에 탐색을 곁들었다. 입력값이 모두 valid한 값으로 들어오지 않았다면 그 값들 처리하는데 난이도가 급상승했겠지만 정말 다행히 1번답게 입력값 검증은 고려할 필요 없이 로직만 제대로 작성하면 무난하게 풀 수 있었다. 필자는 해시 자료구조를 사용해 스트링을 key로, 리스트를 value로 저장하였다. 이렇게 하면 1씩 증가시키면서 검색할 때 이진탐색으로 비교적 빠르게 해결할 수 있기 때문이다. (파이썬 내장모듈 만세)

2번은 탐색범위가 제한되어 있어 별 생각없이 dfs로 완전탐색을 수행해도 해결이 가능해보인다. 다만 필자는 투포인터로 풀었다. 카운트를 깎아야 하는지 여부와 카운트가 0이 되었을 때의 로직을 잘 고려하면 비교적 빠르게 해결할 수 있다.

3번은 개인적으로 검색이 허용되지 않았다면 카카오를 제외한 기업이 출제할 수 있는 가장 난이도가 까다로운 문제이지 않을까 생각한다. 물건을 쌓는 로직과 제거하는 로직, 만약 제거작업이 수행되면 나머지 물건을 아래로 내려주는 로직까지도 작성해야 했다. 구현 + 알고리즘으로 출제되었기에 저번 네이버 코딩테스트 4번 정도에 해당하는 난이도가 아니었나 싶다. 필자도 그냥 프렌즈 4블록과 뿌요뿌요 2문제에 대한 풀이를 검색해서 출제된 문제에 맞게 코드를 변형해 문제를 해결했다. 1시간 동안 1, 2, 4번을 해결하고 3번에 대략 1시간을 쏟은 듯하다. 사용된 알고리즘은 bfs와 나머지는 배열을 이용한 구현.

4번은 SQL 문제로 풀이는 여러 개가 있을 수 있으나 SQL에 대한 레퍼런스가 워낙 다들 잘 나와있어 검색해서 후딱 풀었다. 로직 자체는 간단하다. WHERE과 NOT IN, ORDER BY 연산만 쓰면 일단 성능은 모르겠고 결과는 올바르게 뽑힌다.

히든케이스 채점결과를 알려준 덕분에 필자는 전부 100점을 얻어 올솔하였음을 알 수 있었다. 난이도 체감은 이번에 출제된 데브매칭 3번 문제보다 조금 쉽지만 알고리즘 적용없이 구현만으로 풀 수 있는 문제가 나온다면 정확히 저번 2021 하반기 네이버 코딩테스트 정도의 난이도였다고 생각한다. 다만 데브매칭으로는 채용 인원이 거의 없대서 왜 그런가 찾아보니 채용 시 계약 연봉의 7%를 프로그래머스에 내야 한단다... 기업 홍보 및 전형이 있음을 알리는 목적으로 후원한다는 이야기다. 따라서 서류조차 검토하지 않는 기업이 대다수라 하니 그냥 코딩테스트 경험과 실력체크에 의의를 두어야겠다.

후속 포스팅

2021 Dev-Matching: 웹 백엔드 개발자(하반기) 추가 전형 진행 후기

전혀 응시하게 될 거라곤 생각하지 못했던 코딩테스트였다. 카카오에 입사하신 학교 선배도 네이버는 서탈하셨는데 내가 되겠냐... 하고 접수만 던져놓고 잊고있었는데 코딩테스트 응시 자격 메일이 와서 놀랐었다. 아무래도 앱 출시 경험과 2지망 직군에 모바일로 비벼넣는 게 조금 유효했었나 보다. 전날 화이자 2차를 맞아서 부작용 이슈가 있었지만 실력에 지장이 갈 정도로 심하진 않았던 듯하여 천만다행이었다. 카카오 코테 물먹고 엄청나게 낙심하여 거진 3주 동안 알고리즘은 거들떠도 보지 않았더니 실력이 꽤나 녹슬었다는 생각이 든다.

난이도는 라인, 삼성보다 쉽게 기본 코딩 스킬 위주로 나온다길래 안심하고 갔는데 아니었다. 누가 네이버 코테 쉽다고 했냐... 문제가 어렵지는 않았으나 구현으로만 거진 3문제, 알고리즘 문제마저도 백트래킹 완전탐색이 주요한 문제라 사실상 구현이었다. 2시간 내로 4문제를 완전히 해결하려면 모든 문제에 대한 직관이 막힘없어야 하고 구현 실력도 어느정도 있어야 했다. 얼추 1시간 30분 동안 3문제 테스트 케이스를 통과시키고 30분 동안 4번을 봤으나 해결하지 못하고 테스트를 마쳤다.

1번에서 적잖은 충격을 받았다. 보통 1번이라 함은 적당한 스트링 다루기로 몸풀기 날먹 문제를 던져주기 마련인데 조금의 고민이 필요했던 문제였다. 테스트 케이스 규모는 작으나 조건에 맞게끔 분기문을 작성하여 탐색을 진행해야 했다. 최솟값의 개수가 복수이거나 상대방이 요구하는 종류의 내 숫자와 나의 최솟값의 차이가 1이면 어떻게 분기를 처리해야 하는지 고민이 필요했다. 분기 처리를 하다보니 1번에서 30분 소요.

2번은 큐라는 기본적인 자료구조를 내면서도 이리 신선하게 낼 수 있다는 점에 놀랐다. p값을 다루는 로직이 핵심이 되었다 생각한다. 전체 원소 개수를 별도의 변수로 관리하여 pop연산 시 발생할 수 있는 상황에 따라 요구조건에 맞게 분기문을 작성해야 했다. 개인적으로는 약 20분 정도 소요되어 1번보다 2번이 쉬웠다 생각한다. 최근 코딩테스트가 요구조건에 맞게 분기문을 정확하게 작성하는가에 대한 검증 문제들이 빈출되고 있는데 12번이 그러한 유형이라 생각한다.

3번은 보면서도 구현실력을 보려고 작정했음을 알 수 있었다. 2차원 배열 주고서 방향에 따라 직사각 배열의 부분 사각형 영역을 대각 반전하라는 요구사항인데 다른 이들은 보다 쉽게 공식을 써서 해결한 듯 하다. 필자는 그냥 반전할 부분 배열을 따로 빼내서 새롭게 좌표기준을 설정하고 반전시킨 뒤 변환된 좌표기준을 역으로 접근하여 갱신하는 방식을 채택했다. 수학적 지식을 활용하면 모를까 알고리즘으로 빠르게 구현하는 문제가 아니었기에 상당한 시간이 소요되었다. 거진 4-50분을 사용하였다.

4번은 백트래킹을 이용한 완전탐색이라는 점은 알았으나 주어진 제시조건에 맞춰서 새로운 그래프를 생성한 뒤 각 노드에 대해 이미 배치가 완료된 노드로의 경로 접근이 가능한지 검증하는 로직을 작성해야 했다. 이 함수를 작성할 수 있어야 4번 문제 해결이 가능했는데 유니온 파인드로 풀어야 하나 고민하던 중 결국 경로 검증 함수를 작성하지 못했다. 3번까지 해결하고서 남은 30분 동안 삽질하던 중 슬프지만 별 소득 없이 종료해야 했다.

총평은 점점 알고리즘만 사용해서 후딱 풀 수 있는 문제들은 지양하되 지문을 제대로 읽어서 요구조건에 맞게 구현하는 문제가 빈출하고 있다. 역시 기업 입사 코딩테스트 알고리즘 문제는 군더더기 없이 지문이 깔끔하다. 그래도 역시 제한시간 2시간으로 설정해놓고 구현을 4문제를 준다는 게 푸는 응시자 입장에서는 체력 소모가 확실하다... 다른 분들의 후기를 들어보니 저번보다는 확실히 어려웠다는데 점점 고여가는 이 시장을 생각하면 저번과 비슷하게 3솔컷이지 않을까. 나로서도 알고리즘을 어느정도 공부했다면 3솔은 해야했다 생각하기에 서류 점수가 평균점 정도라면 3솔이 합격컷으로 예상된다. 그리고 내 서류는 평균점일리가 없기에 '-`... 일단 기대는 접고 마저 하던 포폴 준비나 하러 가야겠다.

결과 : 기술면접 1차 통보받았습니다. 힘들 수도 있겠다 싶었는데 좋게 봐주신 듯 하네요. 네이버 면접은 알고리즘, 기본 CS, 개발 언어 이해, 포트폴리오 설명 등으로 진행되고 면접관에 따라 진행 방식이 많이 갈린다고는 하는데 포트폴리오가 없는 상태이니 블로그에 정리해둔 CS, 알고리즘, 개발언어를 리마인딩 하고 가려 합니다.

코딩테스트 결과

- 후속포스팅

2021 하반기 네이버 1차 면접 후기

+ Recent posts