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에만 만든다고 한다.)
- 보통 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 개수를 의미 한다.
'Back_End(Ruby on Rails)' 카테고리의 다른 글
URL 주소 입력부터 웹 브라우저 화면 출력까지 과정 (0) | 2020.04.12 |
---|---|
Rails_추천 시스템에 Redis 적용(Implementaion of Redis in Ruby on Rails) (0) | 2020.02.14 |
Rails Application Request/Response Cycle(레일즈 애플리케이션은 서버에서 어떻게 작동할까?) (2) | 2020.02.10 |
RubyOnRails/Model Association (0) | 2020.02.10 |
Rails Transaction Isolation Level (트랜잭션 격리 레벨) (0) | 2020.02.10 |