< 가비지 컬렉션이란? >

Java에서 가비지 컬렉션(Garbage Collection, 이하 GC)은 프로그램이 동적으로 할당한 메모리를 자동으로 관리하는 과정이다. 이는 프로그래머의 잘못으로 인한 메모리 누수 및 메모리 부족 문제를 방지하는데 매우 중요한 역할을 한다.

C/C++과 같은 언어에서는 프로그래머가 객체를 생성하고 파괴하는 것을 직접 관리해야 하는데. 이 과정에서 프로그래머의 실수로 불필요한 객체가 제거되지 않는다면, 시간이 지남에 따라 메모리 공간이 부족해져 프로그램이 비정상적으로 종료될 수 있다. 이러한 문제를 방지하기 위해 Java에서는 GC라는 기능을 제공해준다. GC는 더 이상 사용되지 않는 객체를 자동으로 감지하여 메모리에서 제거하는 역할을 한다.

< 가비지 컬렉션의 원리 >

Java의 GC는 자동적으로 작동한다. 이 과정은 Heap 메모리를 살펴보고 사용 중인 객체와 사용하지 않는 객체를 구분하여 사용하지 않는 객체를 삭제하는 과정이다. 여기서 사용 중인 객체란 프로그램의 어떤 부분이라도 그 객체에 대한 참조를 가지고 있는 객체를 의미하며, 사용하지 않는 객체란 프로그램의 어떤 부분도 해당 객체를 참조하고 있지 않는 객체를 의미한다.

 

< 가비지 컬렉션의 동작 방식 >

Minor GC: 새로운 객체가 생성되면 처음에는 'Young Generation'이라는 힙 영역에 배치되고, 'Young Generation' 영역이 가득 차면, GC는 이 영역에서 더 이상 참조되지 않는 객체들을 제거하는 Minor GC를 수행한다.


Major GC (Full GC): Young 영역에서 오랫동안 살아남은 객체들은 'Old Generation' 영역으로 이동된다. 이 영역에서는 객체들이 덜 빈번하게 제거되기 때문에, GC는 주로 Minor GC에 비해 덜 빈번하게 발생하는 Major GC를 수행한다.

 

 


실제 프로그램에서는 GC가 실행되면, GC를 실행하는 스레드외에 나머지 스레드는 멈춘다.

Minor GC같은 경우 영역이 작기 때문에  잠깐 멈추는 것이기에 Impact가 적지만, 만약에 Old Generation이 가득 차서 Major GC가 발생하면 오래된 시간 동안 프로그램이 동작하지 않을 수 있다. 그러면 큰 문제가 생길 수 있기에 주의해야 한다. 

 

< GC로 인해 애플리케이션이 멈추는 시간을 최소화하는 방법 >

 

Heap 사이즈 조정: GC가 발생하는 주된 이유는 힙 메모리가 부족하기 때문이다. 따라서 힙 메모리를 적절하게 확장하는 것은 GC를 효과적으로 관리하는 방법 중 하나다. 하지만 너무 큰 힙 사이즈는 GC 시 정지 시간을 늘릴 수 있으므로 적절한 사이즈 조정이 필요하다.

GC 알고리즘 선택: Java는 서로 다른 GC 알고리즘을 제공하며, 각 알고리즘은 다른 유형의 워크로드에 적합하다. 예를 들어, G1 (Garbage-First) GC와 CMS (Concurrent Mark Sweep) GC는 GC 정지 시간을 최소화하는 데 초점을 맞추고 있다. ZGC (Z Garbage Collector)나 Shenandoah와 같은 알고리즘들은 정지 시간을 매우 짧게 유지하면서 대용량 힙을 관리할 수 있다.

객체 할당과 생존 기간 최적화: 객체의 생명 주기를 최적화하면 GC가 더 효율적으로 작동할 수 있다. 장기간 살아있는 객체를 줄이고, 불필요한 객체 생성을 피하는 것이 중요하다. 이렇게 하면 Young Generation에서 대부분의 객체가 처리되고, Major GC를 피할 수 있다.

GC 로그 분석: GC 로그를 주기적으로 분석하면 GC의 동작 방식을 더 잘 이해하고 문제를 조기에 발견할 수 있다. GC 로그는 어떤 종류의 GC 이벤트가 발생했는지, 얼마나 자주 발생했는지, 그리고 얼마나 오래 걸렸는지 등의 중요한 정보를 제공한다.

자바 버전 업데이트: 새로운 자바 버전은 종종 성능 개선과 함께 GC 알고리즘의 개선을 포함하고 있다. 최신 버전의 Java를 사용하면 GC 성능이 향상될 수 있다.

 

 

 

 

Reference : https://www.geeksforgeeks.org/garbage-collection-java/

 

Garbage Collection in Java - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

'Java' 카테고리의 다른 글

Thread async in Java  (0) 2023.06.02
Assert.isTrue()  (0) 2023.05.15
Wrapper Class  (0) 2023.05.14
05.인스턴스 생성과 힙 메모리  (0) 2023.04.23
04.객체의 속성은 멤버 변수로, 객체의 기능은 메서드로 구현한다.  (0) 2023.04.23

🤔 < 스레드란? >

Thread는 Process 내에서 실행되는 여러 흐름 단위를 말한다. 각각의 Thread는 독립적으로 작동하며, 여러 개의 스레드가 동시에 실행될 수 있다. 이를 통해 프로그램의 응답성을 향상시키고, 프로세서를 보다 효율적으로 사용할 수 있다.

예를 들어, 한 프로그램에서 파일을 다운로드하는 작업과  사용자 입력을 처리하는 작업이 동시에 진행되어야 한다면, 이 두 작업을 각각의 Thread에서 처리할 수 있다.

🌳 < 자바에서 Thread 사용하기 >

Java에서는 "Thread" 클래스를 직접 상속받거나, 'Runnalbe' 인터페이스를 구현하는 방식으로 스레드를 생성할 수 있다.

class MyRunnable implements Runnable {
    public void run() {
        // 스레드에서 실행할 작업을 구현
    }
}

public class Main {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start();  // 스레드 실행
    }
}

🤔 < 동기화란? >

동기화는 여러 스레드가 동시에 공유 데이터에 접근하는 것을 제어하는 메커니즘이다. 이는 데이터 일관성을 유지하고, 동시 수정으로 인한 오류를 방지하는데 필요하다.

예를 들어, 두 개의 스레드가 동시에 같은 계좌에서 돈을 출금하는 상황을 생각해보면. 이 때 동기화가 되지 않으면, 두 Thread가 동시에 잔액을 확인하고 동시에 돈을 출금하게 되어, 실제 잔액보다 더 많은 돈이 출금될 수 있다.

🌳 < 자바에서 async 사용하기 >

자바에서는 synchronized 키워드를 사용하여 동기화를 구현할 수 있다. synchronized 키워드는 메소드 또는 블록에 적용할 수 있다. synchronized가 적용된 메소드 또는 블록은 한 번에 하나의 스레드만 접근할 수 있다.

class SharedResource {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {

 

'Java' 카테고리의 다른 글

Java Garbage Collection  (0) 2023.06.07
Assert.isTrue()  (0) 2023.05.15
Wrapper Class  (0) 2023.05.14
05.인스턴스 생성과 힙 메모리  (0) 2023.04.23
04.객체의 속성은 멤버 변수로, 객체의 기능은 메서드로 구현한다.  (0) 2023.04.23

Assert.isTrue()는 Spring Framework에서 제공하는 Assertion 유틸리티 클래스인 Assert 클래스의 메소드 중 하나로, 주어진 boolean 표현식이 참(true)인지를 검사하고, 만약 그렇지 않으면 예외를 발생시킨다.

Assert.isTrue() 메소드는 다음과 같은 형태로 사용할 수 있다.

publicstaticvoidisTrue(boolean expression, String message)

여기서 expression은 검사할 "boolean" 표현식이며, message는 예외가 발생했을 때 출력할 "메시지"다.

아래는 Assert.isTrue() 예시 코드.

import org.springframework.util.Assert;

public class Example {
    public void doSomething(int value) {
      //value > 0 <- expression, "value must be greater than 0" <- message
        Assert.isTrue(value > 0, "value must be greater than 0");
  
    }
}

위 코드에서 Assert.isTrue() 메소드를 사용하여 value 변수가 0보다 큰지를 검사한다. 만약 value 변수가 0 이하의 값이라면 IllegalArgumentException 예외가 발생하며, 예외 메시지로는 "value must be greater than 0"가 출력된다.(Custom Error Message를 써도 좋다.)

즉, Assert.isTrue() 메소드는 주어진 조건이 참인지 검사하여, 그렇지 않을 경우 예외를 발생시킴으로써 코드의 안정성과 신뢰성을 높이는 데 사용된다.

true면 아무 메세지가 출력되지 않는다.

'Java' 카테고리의 다른 글

Java Garbage Collection  (0) 2023.06.07
Thread async in Java  (0) 2023.06.02
Wrapper Class  (0) 2023.05.14
05.인스턴스 생성과 힙 메모리  (0) 2023.04.23
04.객체의 속성은 멤버 변수로, 객체의 기능은 메서드로 구현한다.  (0) 2023.04.23

< Wrapper Class(래퍼 클래스)란? >

Java에서 "기본 자료형"(Primitive Data Type)을 "객체(Object)"로 다루기 위해 제공하는 클래스.

기본 자료형에 각각 대응하는 래퍼 클래스가 1:1로 존재한다.

이를 통해 기본 타입의 값을 객체로 변환하거나 객체에서 기본 타입의 값을 추출할 수 있다.

각 기본 자료형에 대응하는 래퍼 클래스는 다음과 같다.


boolean -> java.lang.Boolean

byte -> java.lang.Byte

char -> java.lang.Character

short -> java.lang.Short

int -> java.lang.Integer

long -> java.lang.Long

float -> java.lang.Float

double -> java.lang.Double


래퍼 클래스를 사용하면 기본 자료형에 대해 객체지향적인 기능을 사용할 수 있다.

예를 들어, 래퍼 클래스의 인스턴스를 컬렉션에 저장 혹은 메서드에서 객체 형태로 전달할 수 있다.

Java에서는 오토박싱(Auto-boxing)과 오토언박싱(Auto-unboxing) 기능을 제공하여 기본 자료형과 래퍼 클래스 간의 변환을 자동으로 처리할 수 있다. 이를 통해 개발자는 래퍼 클래스와 기본 자료형 간의 변환 작업을 명시적으로 처리할 필요가 없어져 코드 작성이 간결해진다.

전 시간에 객체를 클래스로 부터 New를 통해 생성을 하게 되면, Instance가 생성되고

Heap이라는 Memory에 들어가게 되는데, Instance와 Heap Memory가 어떻게 만들어 지는 지, 이 Heap Memory가 어떻게 관리 되는지 살펴보자.

 

 

인스턴스 (Instance)


  • 클래스는 객체의 속성을 정의 하고, 기능을 구현하여 만들어 놓은 코드 상태
  • 실제 클래스 기반으로 생성된 객체(인스턴스)는 각각 다른 멤버 변수 값을 가지게 된다. 가령 학생 클래스에서 생성된 각각의 인스턴스는 각각 다른 이름, 학번, 학년등의 값을 가지게 된다.

위는 지난 번에 만들어 본 코드인데, "studentLee", "studentKim" 이라는 두 개의

Instance가 있는데, 각각의 인스턴스에 studentID,studentName,address를 각각 다르게 변수를 할당 했다. 이 것이 가능한 이유는 서로 다른 메모리에 위치 하고 있기 때문이다. 만약 같은 메모리를 쓰고 있다고 가정한다면 다른 이름을 줄 수가 없고,다른 이름이 출력 되지도 않을 것이다. 즉, Class는 하나 이지만, 그 것으로부터 생성된 Instance는 여러 개 일 수도 있다, 각각 다른 메모리에 위치한다. 그 곳이 어디냐면 Heap이라는 동적 메모리다.

  • new 키워드를 사용하여 인스턴스를 생성 한다.

 

 

힙 메모리(Heap Memory)


  • 생성된 인스턴스는 동적 메모리(Heap Memory)에 할당 된다. 할당 할 때, Java는 "new"를 쓰고, C++ new, C는 malloc을 쓴다. 그 메모리는 동적 메모리(Heap)라고 한다. 그 메모리는 쓰고 나서는 해제를 시켜야 한다.

위의 사진을 보면, System.out.println(studentKim);

System.out.println(studentLee);를 통해 Console창에 출력 해보면

36aa7bc2,76ccd017같은 것이 출력이 되는데 이것은 JVM이 만들어준 가상 주소다. studentLee같은 경우는 지역변수인데, 여기서 주소값을 가르치는 곳이 Instance의 주소값이라는 것이다.

그래서, studentLee라는 것을 참조변수라고 하고, Memory Address(36aa7bc2,76ccd017)를 참조 값이라고 한다.

생성된 인스턴스도 객체라고 부르는데, 그것은 객체라기 보단 인스턴스라고 부르는 것이 구별하기 좋다.

  • C나 C++ 언어에서는 사용한 동적 메모리를 프로그래머가 해제 시켜야 한다(free()나 delete 이용)
  • 자바에서 Gabage Collector가 주기적으로 사용하지 않은 메모리를 수거한다.
  • 하나의 클래스로 부터 여러개의 인스턴스가 생성되고 각각 다른 메모리 주소를 가지게 된다.

 

참고: FastCampus 

한 번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online.

학생 클래스를 정의 하고 이를 사용 해보자.

package ch04

public class Student {

public int studentID;
public String studentName;
public String address;

public void showStudentInfo(){ 
   System.out.println( studentID + "학번 학생의 이름은 " + studentName + " 이고, 주소는 " + address + "입니다. ");
 }
 //학생 이름을 지정 하거나 반환하는 메서드를 만들어 보자.
 //반환값은 String으로..
 public String getStudentName() {
 return studentName;
  }
 public void setStudentName(String name) {
    studentName = name;
  }
  
}

클래스를 이대로 만들어 보고, 클래스를 쓰는 클래스를 따로 만들어 보자.

StudentTest라는 클래스를 만들어보자.

package ch04;

public class StudentTest {
  public static void main(String[] args) {
    //데이터 타입을 클래스를 가져다 쓸 경우, 크기가 정해져 있는 것은 아니다.
    Student studentLee = new Student();
    //클래스가 있으면 클래스를 기반으로 여러개의 인스턴스 변수가 생성 될 수 있다.
    
    studentLee.studentID = 12345;
    studentLee.setStudentName("Lee");
    studentLee.address = "서울 강남구";
    
    studentLee.showStudentInfo(); //12345학번 학생의 이름은 Lee이고, 주소는 서울 강남구 입니다.
    
    Student studentKim = new Student();
    studentKim.studentID = 54321;
    studentKim.studentNam = "Kim";
    studentKim.address = "경기도 성남시";
    
    studentKim.showStudentInfo(); //54321학번 학생의 이름은 Kim이고, 주소는 경기도 성남시입니다.
    
    
  }
}

인스턴스는 생성자는 new를 통해 만들 수가 있고,

인스턴스가 생성이 되는 곳을 Heap memory이고, 지역변수는 Stack memory이다.

다음 시간에는 Heap memory가 어떻게 관리 되는지 알아보자.

 

 

참고: FastCampus

 

출처: FastCampus 한 번에 끝내는 Java/Spring 웹 개발 마스터 객체 지향 입문

03. 함수와 메서드


함수란(function)

1.하나의 기능을 수행하는 일련의 코드

2.구현된(정의된)함수는 호출하여 사용하고 호출된 함수는 기능이 끝나면 제어가 반환됨.

3.함수로 구현된 하나의 기능은 여러 곳에서 동일한 방식으로 호출되어 사용될 수 있다.

한 군데에서 기능을 구현하면 더한다라는 기능을 갖다 쓰면 된다.


함수 정의하기


함수는 이름, 매개 변수, 반환 값, 함수 몸체(body)로 구성된다.

int add(int num1, int num2) {
  int result;
  result = num1 + num2;
  return result;
}

반환이 없을 경우에는 void add() {

}이렇게 쓴다. 매개변수는 아무 것도 안써도 된다.


함수 구현하기 예제


public class FunctionTest {
  
  public static int addNum(int num1, int num2) {
    
    int result;
    result = num1 + num2;
    return result;
  }
  public static void sayHello(String greeting) {
    
    System.out.println(greeting);
  }
  
  public static int calcSum()
  {
    int sum = 0;
    int i;
    
    for(i = 0; i<=100; i++) {
      sum += i;
    }
return sum;
    
  }
  public static void main(String[] args) {
    
    int n1 = 10;
    int n2 = 20;
    
    int total = addNum(n1, n2);
    System.out.println(total);//30
    
    sayHello("안녕하세요");//안녕하세요
    
    total = calcSum();
    System.out.println(total);//5050
  }
}

함수 호출과 스택 메모리


스택: 함수가 호출될 때 지역 변수들이 사용하는 메모리

함수의 수행이 끝나면 자동으로 반환 되는 메모리

public class FunctionTest {
  
  public static int addNum(int num1, int num2) {
    
    int result;
    result = num1 + num2;
    return result;
  }
  public static void sayHello(String greeting) {
    
    System.out.println(greeting);
  }
  
  public static int calcSum()
  {
    int sum = 0;
    int i;
    
    for(i = 0; i<=100; i++) {
      sum += i;
    }
return sum;
    
  }
  public static void main(String[] args) {
    
    int n1 = 10;
    int n2 = 20;
    
    int total = addNum(n1, n2);
    System.out.println(total);//30
    
    sayHello("안녕하세요");//안녕하세요
    
    total = calcSum();
    System.out.println(total);//5050
  }
}

main 메서드에서 호출되지 않은 메서드들은 스택 메모리에 저장되지 않는다. 스택 메모리는 메서드 호출에 대한 스택 프레임만 저장하므로, 호출되지 않은 메서드는 스택 메모리에 저장되지 않는다. 호출되지 않은 메서드의 경우, 실행 시점에 스택 메모리에 영향을 주지 않는다.

이 코드에서 스택 메모리의 삭제가 발생하는 부분은 다음과 같다:

addNum 메서드가 호출되고 종료될 때 (return 값 반환)

sayHello 메서드가 호출되고 종료될 때 (메서드 실행 완료)

calcSum 메서드가 호출되고 종료될 때 (return 값 반환)

main 메서드가 종료될 때 (메서드 실행 완료)

따라서 예시에서 총 4번의 스택 프레임 삭제가 발생하며, 이는 스택 메모리에서 각 스택 프레임이 삭제되는 것을 의미한다.


메서드 (method)


1.객체의 기능을 구현하기 위해 클래스 내부에 구현되는 함수

2.C++에서는 멤버 함수(member function)이라고도 한다.

3.메서드를 구현함으로써 객체의 기능이 구현 된다.

4.메서드의 이름은 그 객체를 사용하는 객체(클라이언트)에 맞게 짓는 것이 좋다.

객체가 있으면 다른객체가 그 객체를 사용하는 경우가 있다.

사용 할 때 메서드를 호출 할 떄, 호출하는 입장에서 명령하는 것이 좋다.

getStudentName()

5.클래스안에 있고 클래스의 멤버 변수들을 활용해서 구현한다.

출처: FastCampus 한 번에 끝내는 Java/Spring 웹 개발 마스터 객체 지향 입문

 

생활 속에서 객체 찾아 클래스로 구현해 보기

객체를 찾아보자.

1.온라인 쇼핑몰에 회원 로그인을 하고 여러 판매자가 판매하고 있는 제품 중 하나를 골라 주문을 한다.

여기서는 온라인 쇼핑몰 자체는 System이 되고

회원,판매자,제품,주문이 객체에 해당 된다.


2.아침에 회사에 가는 길에 별다방 커피숍에 들려 아이스 카페라떼를 주문 했다.

여기서 객체는 나,회사,커피숍,커피,주문,알바


3.성적확인을 위해 학사 관리 시스템에 로그인 하여 수강 한 과목들의 성적을 확인 했다.

학생,과목,교수,강의실,통계,통계 방법 등 보이지 않는 것의 명사 또한 객체가 된다.

클래스는 객체의 청사진 이다.

객체의 속성은 클래스의 멤버 변수로 선언 한다.

//학생 클래스

Public class Student {
//속성,멤버 변수
 int studentNumber;
 String studentName;
 int majorCode;
 String majorName;
 int grade;
}
//주문 클래스
public class Order {
  int orderId;
  String buyerId;
  String sellerId;
  int productId;
  String orderData;
}
//회원 클래스
public class UserInfo {
  //소문자로부터 시작해서 대문자
  String userId;
  String userPassWord;
  String userName;
  String userAddress;
  int phoneNumber; 
}

절차 지향 프로그래밍의 대표적인 언어-> C언어

시간의 흐름에 따라 프로그래밍

일어난다->씻는다->밥을 먹는다->버스를 탄다->요금을 지불한다->학교 도착

객체 지향 프로그래밍 (Object Oriented Programming)

학교를 가는 과정엔

학생,버스,학교,밥이 있을 수 있다.

그 객체 사이의 관계가 있다. 학생이 버스를 탄다라고 했을 때,

학생이 버스를 타게 되면 돈을 내야되고

버스는 승객이 늘어나고 매출이 올라가는 등 관계가 있다.

그런 관계를 가지고 프로그래밍을 하는 것이 객체 지향 프로그래밍이다.

C++,C#,Python,Javascript가 속한다.

그렇다면 객체 지향 프로그램은 어떻게 구현하는가?

객체를 정의하고

각 객체 제공하는 기능들을 구현하고

각 객체가 제공하는 기능들 간의 소통(메세지 전달)을 통하여 객체간의 협력을 구현

 

 

 

출처: FastCampus 한 번에 끝내는 Java/Spring 웹 개발 마스터 객체 지향 입문

 

+ Recent posts