JAVA 메모리 관리 (스택, 힙)

마지막 업데이트: 2022년 7월 12일 | 0개 댓글
  • 네이버 블로그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 트위터 공유하기
  • 카카오스토리 공유하기
  • 원시 타입의 데이터의 경우 변수와 값이 모두 stack에 저장
  • 오브젝트타입인 string형 데이터는 변수(참조값)는 stack에 값(실제값)은 heap에 저장

영역 바이너리 옵션 타입

  • JVM(Java Virtual Machine, 자바가상머신)

JVM의 메모리관리

C나 C++에서는 OS레벨의 JAVA 메모리 관리 (스택, 힙) 메모리에 직접 접근하기 때문에, free() 메소드를 호출하여 할당받은 메모리를 해제해주어야 한다. 그렇지 않으면 메모리 누수가 발생하여 프로그램의 응답속도가 늦어지다 결국 OOM(OutOfMemory) 오류로 프로그램이 종료되고, 다른 프로그램에 영향을 끼칠 수도 있다.

반면, 자바는 OS의 메모리 영역에 직접 접근하지 않고, JVM이라는 가상머신을 통해 간접적으로 접근한다. JVM은 C로 쓰여진 프로그램으로, 오브젝트가 필요해지지 않는 시점에서 알아서 free()를 수행하여 메모리를 확보한다.

프로그램 실행시 JVM 옵션을 주어서 OS에 요청한 사이즈 만큼의 메모리를 할당 받아 실행하게 된다. 할당받은 JAVA 메모리 관리 (스택, 힙) 메모리 이상을 사용하게 되면, 에러가 나면서 자동적으로 프로그램이 종료된다. 그러므로 현재 프로세스에서 메모리 누수가 발생하더라도 현재 실행중인 프로그램만 죽고, 다른 프로그램에는 영향을 끼치지 않는다.

이렇게 자바는 가상머신을 사용함으로써 OS레벨에서의 memory leak이 불가능하게 된다는 장점이 있다.

Garbage Collecting 과정

Heap영역에서 더 이상 사용되지 않는 오브젝트를 찾아, 가비지 컬렉션을 담당하는 프로세스가 자동으로 메모리에서 제거한다.

  • Stack : 정적으로 할당한 메모리 영역
    • 원시 타입의 데이터가 값과 함께 할당된다.
    • Heap영역에 생성된 오브젝트 타입 데이터의 참조값이 할당된다.
    • 모든 오브젝트 타입의 데이터가 할당된다.

    runtime시 stack과 heap에 메모리 할당

    image

    • 원시 타입의 데이터의 경우 변수와 값이 모두 stack에 저장
    • 오브젝트타입인 string형 데이터는 변수(참조값)는 stack에 값(실제값)은 heap에 저장

    • 실행이 종료되면 stack에 할당되었던 데이터는 삭제
    • 하지만, heap 영역에 할당된 데이터는 삭제되지 않고 남아있고, 이것을 Unreachable Object라고 부름

    영역 바이너리 옵션 타입

    - Java에서 메모리관리를 하는 방법에 관해

    Java는 OS의 메모리 영역에 직접적으로 접근하지 않고 JVM(Java Virtual Machine)을 JAVA 메모리 관리 (스택, 힙) 이용하여 간접적으로 접근한다.

    프로그램 실행시 JVM 옵션을 주어서 OS에 요청한 사이즈 만큼의 메모리를 할당받아 실행하게 되는데,

    할당받은 메모리 이상을 사용하게 되면 에러가 나게 된다.JAVA 메모리 관리 (스택, 힙)

    GC(Garbage Collection)는 백그라운드에서 사용되지 않는 객체를 정리하고 메모리를 확보한다.

    JAVA에서 메모리가 실제로 어떻게 동작하는지를 알아야 높은 성능과 최적화된 애플리케이션을 만들 수 있고, 문제가 발생해도

    빠르게 메모리 누수를 찾을 수 있다.

    Image from ' https://dzone.com/articles/java-memory-management '

    Stack

    • Heap 영역에 생성된 Object 타입의 데이터의 참조값이 할당된다.
    • 원시타입의 JAVA 메모리 관리 (스택, 힙) 데이터가 값과 함께 할당된다.
    • 지역변수들은 scope 에 따른 visibility 를 가진다.
    • 각 Thread 는 자신만의 stack 을 가진다.

    Stack은 Heap 객체의 참조 실제 값 자체를 갖는 데이터 (Java 기본형 byte, short, int, long, double, float, boolean, char)를 저장
    Java의 Stack 메모리는 스레드당 할당. 스레드가 생성되고 시작될때 스레드는 자신의 Stack 메모리를 갖고 , 다른 스레드 Stack 메모리에 접근 할 수 없다.

    Heep

    • Heap 영역에는 주로 긴 생명주기를 가지는 데이터들이 저장된다. (대부분의 오브젝트는 크기가 크고, 서로 다른 코드블럭에서 공유되는 경우가 많다)
    • 애플리케이션의 모든 메모리 중 stack 에 있는 데이터를 제외한 부분이라고 보면 된다.
    • 모든 Object 타입(Integer, String, ArrayList, . )은 heap 영역에 생성된다.
    • 몇개의 스레드가 존재하든 상관없이 단 하나의 heap 영역만 존재한다.
    • Heap 영역에 있는 오브젝트들을 가리키는 레퍼런스 변수가 stack 에 올라가게 된다.

    Heap은 메모레의 실제 객체를 저장한다. Heap JAVA 메모리 관리 (스택, 힙) 영역은 주로 긴 생명주기를 갖는 데이터들이 저장된다.
    모든 Object 타입(Integer, String, JAVA 메모리 관리 (스택, 힙) ArrayList, HashMap) 등이 Heap 영역에 생성된다,
    Heap 영역에 있는 Object들을 가리키는 레퍼런스 변수가 Stack 에 저장된다.

    영역 바이너리 옵션 타입

    [C++ 입문자에서 벗어나기]Chapter_2: 선언과 정의#2

    이번 포스팅에서는 "초기화된 전역 변수와 초기화되지 않은 전역 변수"에 대해서 다뤄볼 생각입니다.

    [초기화된 전역 변수와 초기화되지 않은 전역 변수]

    아래의 코드를 봐주시길 바랍니다.

    전역 변수 형태로 총 4개의 변수들이 정의되어 있습니다.

    우리는 이미 이전 포스팅에서 전역 변수가 자동 초기화가됨을 알고 있습니다.

    위 코드를 실행 시키면 0057이라는 출력값이 나오게 된다는 것은 쉽게 알 수 있겠죠.

    그런데 위 전역 변수들은 C++의 어느 가상 메모리 영역에 위치하게 될까요?

    g_C는 확실하게 Data영역에 위치할 것 같습니다.

    5라는 상수로 변수를 초기화하는 정의문을 가지고 있으니까요

    그렇다면 나머지 3개는 어떨까요?

    먼저, g_A에 대해 이야기해봅시다.

    g_A는 어느 값으로도 초기화되지 않으니까 BSS영역일 거 같네요.

    g_B는 0으로 초기화했으니까 Data영역일 거 같습니다.

    그런데 BSS영역은 초기화되지 않은 값들을 넣어놓고 다 0으로 설정해놓는 것인데.

    0으로 초기화하면 정말 Data영역으로 가는건지가 약간 의문스러워서 StackOverflow에 물어봤습니다.

    위 게시글의 답변을 요약하면 이렇습니다.

    -GCC는 기본적으로는 0으로 초기화된 변수들에 대해서 BSS영역에 저장시킵니다.

    이렇게함으로써 실행 바이너리의 크기를 절약할 수 있습니다.

    -GCC 옵션은 기본적으로는 -fzero-initialized-in-bss로 설정되어 있지만 -fno-zero-initialized-in-bss 옵션을 줄 시에는 0으로 초기화된 변수들을 BSS영역이 아닌 Data영역에 저장시킬 수 있습니다.

    그러면 마지막으로 g_D에 대해 이야기해봅시다.

    g_D는 함수로 값을 초기화하는데 결론부터 이야기드리자면 g_D는 BSS영역에 저장됩니다.

    상수로 초기화되는 전역 변수들만이 Data영역에 저장되고 함수(생성자 포함)로 초기화를 진행하는 전역변수들의 경우 BSS영역에 저장되고 프로세스 실행 후에야 함수의 반환값으로 값이 설정됩니다.

    위 코드가 실행될 시에 전역 변수들의 값들이 JAVA 메모리 관리 (스택, 힙) 어떻게 변동되는 지를 순차적으로 간단히 살펴보겠습니다.

    먼저 프로그램을 동작시키면 프로세스가 생성되고 스레드가 생성되며 스레드에서 main함수를 호출하기 이전에 먼저 CRT_Startup 함수를 호출합니다.

    이 때, CRT_Startup함수가 호출되기 이전에 g_A, g_B, g_D는 0으로 g_C는 5로 값이 설정된 상태입니다.

    CRT_Startup이 여러 함수를 호출하다가 초기화 처리 함수를 호출 할 때, g_D는 7이라는 값을 할당받게 됩니다.

    이후에 CRT_Startup이 필요한 모든 함수들이 호출된 다음에서야 main함수가 호출되고 cout함수를 통해 출력문들이 출력되게 됩니다.

    kubectl 치트 시트

    --all-namespaces 를 붙여야 하는 상황이 자주 발생하므로, --all-namespaces 의 축약형을 알아 두는 것이 좋다.

    Kubectl 컨텍스트와 설정

    kubectl 이 통신하고 설정 정보를 수정하는 쿠버네티스 클러스터를 지정한다. 설정 파일에 대한 자세한 정보는 kubeconfig를 이용한 클러스터 간 인증 문서를 참고한다.

    Kubectl apply

    apply 는 쿠버네티스 리소스를 정의하는 파일을 통해 애플리케이션을 관리한다. kubectl apply 를 실행하여 클러스터에 리소스를 생성하고 업데이트한다. 이것은 프로덕션 환경에서 쿠버네티스 애플리케이션을 관리할 때 권장된다. Kubectl Book을 참고한다.

    오브젝트 생성

    쿠버네티스 매니페스트는 JSON이나 YAML로 정의된다. 파일 확장자는 .yaml , .yml , .json 이 사용된다.

    리소스 조회 및 찾기

    리소스 업데이트

    리소스 패치

    리소스 편집

    선호하는 편집기로 모든 API 리소스를 편집할 수 있다.

    리소스 스케일링

    리소스 삭제

    실행 중인 파드와 상호 작용

    컨테이너로/컨테이너에서 파일과 디렉터리 복사

    참고: kubectl cp 명령을 사용하려면 컨테이너 이미지에 'tar' 바이너리가 포함되어 있어야 한다. 'tar'가 없으면, kubectl cp 는 실패할 것이다. 심볼릭 링크, 와일드카드 확장, 파일 모드 보존과 같은 고급 사용 사례에 대해서는 kubectl exec 를 고려해 볼 수 있다.

    디플로이먼트, 서비스와 상호 작용

    노드, 클러스터와 상호 작용

    리소스 타입

    단축명, API 그룹과 함께 지원되는 모든 리소스 유형들, 그것들의 네임스페이스와 종류(Kind)를 나열:

    API 리소스를 탐색하기 위한 다른 작업:

    출력 형식 지정

    특정 형식으로 터미널 창에 세부 사항을 출력하려면, 지원되는 kubectl 명령에 -o (또는 --output ) 플래그를 추가한다.

    출력 형식세부 사항
    -o=custom-columns= 쉼표로 구분된 사용자 정의 열 목록을 사용하여 테이블 출력
    -o=custom-columns-file= 파일에서 사용자 정의 열 템플릿을 사용하여 테이블 출력
    -o=json JSON 형식의 API 오브젝트 출력
    -o=jsonpath= jsonpath 표현식에 정의된 필드 출력
    -o=jsonpath-file= 파일에서 jsonpath 표현식에 정의된 필드 출력
    -o=name 리소스 명만 JAVA 메모리 관리 (스택, 힙) 출력하고 그 외에는 출력하지 않음
    -o=wide 추가 정보가 포함된 일반-텍스트 형식으로 출력하고, 파드의 경우 노드 명이 포함
    -o=yaml YAML 형식의 API 오브젝트 출력

    -o=custom-columns 의 사용 예시:

    더 많은 예제는 kubectl 참조 문서를 참고한다.

    Kubectl 출력 로그 상세 레벨(verbosity)과 디버깅

    Kubectl 로그 상세 레벨(verbosity)은 -v 또는 --v 플래그와 로그 레벨을 나타내는 정수로 제어된다. 일반적인 쿠버네티스 로깅 규칙과 관련 로그 레벨이 여기에 설명되어 있다.

    JAVA 메모리 관리 (스택, 힙)
    로그 레벨세부 사항
    --v=0 일반적으로 클러스터 운영자(JAVA 메모리 관리 (스택, 힙) operator)에게 항상 보여지게 하기에는 유용함.
    --v=1 자세한 정보를 원하지 않는 경우, 적절한 기본 로그 수준.
    --v=2 서비스와 시스템의 중요한 변화와 관련이있는 중요한 로그 메시지에 대한 유용한 정상 상태 정보. 이는 대부분의 시스템에서 권장되는 기본 로그 수준이다.
    --v=3 변경 사항에 대한 확장 정보.
    --v=4 디버그 수준 상세화.
    --v=5 트레이스 수준 상세화.
    --v=6 요청한 리소스를 표시.
    --v=7 HTTP 요청 헤더를 표시.
    --v=8 HTTP 요청 내용을 표시.
    --v=9 내용을 잘라 내지 않고 HTTP 요청 내용을 표시.

    다음 내용

    재사용 스크립트에서 kubectl 사용 방법을 이해하기 위해 kubectl 사용 규칙을 참고한다.

    더 많은 커뮤니티 kubectl 치트시트를 확인한다.

    이 페이지가 도움이 되었나요?

    피드백 감사합니다. 쿠버네티스 사용 방법에 대해서 구체적이고 답변 가능한 질문이 있다면, 다음 링크에서 질문하십시오. Stack Overflow. 원한다면 GitHub 리포지터리에 이슈를 열어서 문제 리포트 또는 개선 제안이 가능합니다..


0 개 댓글

답장을 남겨주세요