본문 바로가기

Back_End(Ruby on Rails)

Ruby 의 Garbage Collection 을 이해할 수 있는 GC 모듈 (Ruby GC Module, which helps to understand the Garbage Collection of Ruby)

반응형

C++을 공부하면서, C++의 특징은 소멸자를 기본적으로 직접 선언하여 메모리 해제도 직접 해준다는 점이다. 근데, Ruby 같은 high level 언어는 메모리 해제를 직접하지 않고, Garbage Collection 이라는 기능을 이용하여 힙 메모리에 할당된 object 가 해제된다. 여기서 궁금한 점은 아무리 Garbage Collection 기능으로 메모리 관리가 저절로 된다고 해도 메모리 누수가 생길 수 있는거 아닌가?(가령, 해제가 안되는 것으로 분류된다든지), 과연 Garbage Collection은 어떤 기준으로 메모리를 해제할까? 라는 점이 궁금했다.

궁금증에 대한 답변은 우선 아래와 같이 요약할 수 있다.

-> object memory가 해제 안되는 경우는 Constant Variable이 해당 object 를 참조하고 있으면, 절대 garbage Collect되지 않는다고 한다. 반대로 그 나머지의 경우에는 Object 를 참조하고 있는 변수가 사라지는 순간 자동으로 Garbage Collection에 들어가서 메모리가 해제될 것이다.

-> 메모리 해제 될 오브젝트는 Freed object 의 갯수 변화로 실험해볼 수 있다. Ruby 에서는 GC라는 Module Class로 이런 것들을 확인해볼 수 있다.

아 그리고, 다른 얘기지만, C++을 같이 공부하면서 알게 된 C++의 특징은 Class 의 Instance 인 Object를 Stack Memory에 바로 올릴 수 있다는 점이다. (Java는 그게 안되고, 오로지 Heap에만 만든다고 한다.)

C++ 에서는 Stack 에 Object를 바로 띄워서 빠르게 Access 할 수 있다.

  • 보통 Rails app은 Java와 같이 object가 생성될 때 heap에 실제 데이터들이 올라가있다고 생각하면 된다.

*free object: 힙 메모리에서 해제된 object 

그럼 다시 본론으로 돌아와서 Ruby 의 Garbage Collection Mechnism의 이해를 도와주는 GC 모듈의 간단한 기능과 Object 관리방법을 간단하게 알아보자. 

  • Object Retention (GC라는 가비지 콜렉터 관련 연산을 정의해둔 Class를 사용)
    • Rails에서 메모리를 많이 잡아먹는 것은 Retaining Object 하는 경우이다. 
    • 만약 Constant가 오브젝트를 참조하고 있으면, 그 오브젝트는 절대 Garbage Collect되지 않는다. (즉, 힙에서 사라지지 않는다.) 

  • 위와 같은 경우를 설명해 보자. 
    • Retained라는  global 변수의 배열안에 “a string”이라는 string 을 넣는 형태
    • 그럼 100,000 개의 포인터를 힙에 만듦(즉, 배열(in Stack)에서는 객체에 대한 참조값만을 저장한다.)
    • 근데, 여기서는 이 100,000개의 오브젝트들이 Garbage Collect 될 수 없다.
    • 왜냐? 글로벌 오브젝트들에 의해 참조되는 오브젝트는 Garbage가 될 수 없기 때문이다.
    • Constant(상수, 변하지 않는거에 의해 참조되면 없어지지 못하겠지?), global Variables, Modules, class가 참조하는 오브젝트는 Garbage Collect될 수 없음
    • 결론은 ?? —> Referecing Object 할 때는 Globally Accesible 한 것들을 피하자.. 

 

  • 만약 그럼 Retaining 하는 Global Variable없이 실행하면?

  • Object Freed는 몇 개일까?  -> Objects Freed: 100005
  • 왜 이렇게 높게 나왔는지?? -> foo 는 더 이상 object Retaining 하지 않았기 때문이다.
  • Retention for Speed
    • 위의 Retained 배열이 있는 코드에서 메모리 사용을 줄이려면.. -> freeze method 사용!

  • 이 경우에도, Objected Freed: 6으로 여전히 프리 오브젝트는 작다. 하지만, Memory Use가 엄청 낮아짐 -> ? -> “a string”으로 할당된 매우 작은 수의 오브젝트만이 retained 되고 reused 되므로..신기하다…. GC.stat(:total_allocated_objects)로 확인해볼 수 있다.
  • Why? -> Ruby Can Store one string object with 100,000 references to that object. 
  • 저 말을 다시 얘기하면, 실제 string object (“a string”)이 담겨있는 힙을 참조하는 포인터가 100,000개가 된다는 것이다. , 매우 적은 object들만이 힙에 할당되서 재사용되는 것이다. 이렇기 때문에 Object Freed는 여전히 작지만, Run time시에 object를 생성하는데 걸리는 시간을 매우 단축시킬 수 있다. (왜냐? -> 힙에 오브젝트를 많이 생성안할거니까.)

 

  • Short Lived Objects: Life Cycle 이 짧은 object
    • 사실 대부분의 오브젝트들은 짧은 생애 주기를 갖고 있음(생애 주기는 메모리 해제를 의미하겠지) -> 언제? -> object가 힙에 생성된 이후에 더이상 그것을 참조하는 레퍼런스가 없을 때 !

  • 위와 같이 ORM 을 이용하여 쿼리를 날릴 때 오브젝트가 생성되고, 실행될 때만 object가 지속된다
  • User 클래스에서 정의된 where이 불러지고, 거기 안에 name Symbol, 그리고, String 클래스로부터 “shneems” 오브젝트가 만들어지지만 금방 사라지게 된다.

 

*total_allocated_object, total_freed_object: process lifetime 동안의 object 개수를 의미 한다.

반응형