Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

내 Ruby 애플리케이션에서 무슨 일이 일어나고 있습니까?

Ruby 애플리케이션에 무슨 일이 일어나고 있는지 궁금하시다면…

멋진 GUI 도구가 없습니다. …

하지만 ObjectSpace 모듈이 있습니다!

객체 공간 애플리케이션의 현재 상태에 대한 정보를 제공합니다.

작동 원리를 알아보겠습니다.

객체 계산

ObjectSpace 사용 프로그램에서 현재 '살아 있는' 개체를 알 수 있습니다.

개체가 살아 있다는 것은 무엇을 의미합니까?

개체를 가리키는 참조가 있는 한 개체는 살아 있습니다. 참조는 변수나 상수와 같은 개체에 액세스하는 방법일 뿐입니다.

개체에 도달할 수 없으면 메모리에서 제거해도 안전하다는 의미입니다.

:

# The variable 'name' holds a reference to the string 'Dave'.
name = 'Dave'

# The 'name' variable now points to 'John'.
# 'Dave' no longer has a reference pointing to it.
name = 'John'

이제 ObjectSpace의 예를 살펴보겠습니다. 실행 중:

require 'objspace'

# This is valid Ruby syntax, but doesn't work on irb/pry
ObjectSpace
  .each_object
  .inject(Hash.new 0) { |h,o| h[o.class] += 1; h }
  .sort_by { |k,v| -v }
  .take(10)
  .each { |klass, count| puts "#{count.to_s.ljust(10)} #{klass}" }


# Copy & paste version (use this for irb/pry)
ObjectSpace.each_object.inject(Hash.new 0) { |h,o| h[o.class] += 1; h }.sort_by { |k,v| -v }.take(10).each { |klass, count| puts "#{count.to_s.ljust(10)} #{klass}" }
를 넣습니다.

그러면 상위 10개 클래스에 대한 개체 수가 포함된 테이블이 인쇄됩니다.

Count      Class
-------------------------
5436       String
315        Class
251        Array
101        Encoding
69         Regexp
45         Hash
26         Module
25         Gem::Version
22         Gem::StubSpecification::StubLine
22         Gem::StubSpecification

메모리 누수가 의심되는 경우 매시간 이 데이터를 기록하고 항상 증가하지만 결코 감소하지 않는 일부 개체 수가 있는지 확인할 수 있습니다.

재미있는 물건

ObjectSpace를 사용하는 경우 정보뿐만 아니라 실제 개체에 액세스할 수 있으므로 모든 문자열의 값을 인쇄하거나 모든 File의 경로를 인쇄하는 것과 같은 재미있는 작업을 수행할 수 있습니다. 개체.

:

ObjectSpace
  .each_object(String)
  .sort_by { |s| s.size }
  .each { |s| p s }

이렇게 하면 크기별로 정렬된 모든 인메모리 문자열이 인쇄됩니다. 스스로 생성한 것이 아니라 Ruby 인터프리터에서 생성한 문자열이 많이 있음을 알 수 있습니다.

실용?

음, 이것은 주로 앱에 대한 통계를 디버깅하고 수집하기 위한 것입니다 🙂

객체 메모리 크기

또 다른 방법은 ObjectSpace.memsize_of를 사용하는 것입니다. 특정 개체의 메모리 크기를 찾습니다.

:

o = "a" * 100
ObjectSpace.memsize_of(o)

한 가지 명심해야 할 점은 다음 문서의 경고입니다.

<블록 인용>

"반품 크기가 불완전하다는 점에 유의하십시오. 이 정보는 힌트로만 다루어야 합니다.”

다른 유형의 개체로 이 방법을 시도하면 몇 가지 흥미로운 점을 발견할 것입니다 , Fixnum과 같이 s는 항상 0을 반환합니다.

ObjectSpace.memsize_of(42)
# 0

그 이유는 Ruby가 내부적으로 Fixnum을 생성하지 않기 때문입니다. 개체에 대한 자세한 내용은 내가 Ruby의 숫자에 대해 쓴 게시물에서 확인할 수 있습니다.

또 다른 흥미로운 것은 문자열입니다:

ObjectSpace.memsize_of("A" * 22)
# 40

ObjectSpace.memsize_of("A" * 23)
# 40

ObjectSpace.memsize_of("A" * 24)
# 65
<블록 인용>

"A" * size를 사용합니다. 입력하지 않고 더 긴 문자열을 만드는 방법으로 🙂

기다리다! 방금 무슨 일이 일어났나요?

글쎄, Ruby에는 24자보다 작은 문자열에 대한 최적화가 내장되어 있다는 것이 밝혀졌습니다. 그래서 그 이후에 메모리 사용이 급증합니다. Pat Shaughnessy의 이 게시물에서 더 자세히 볼 수 있습니다.

별칭 메서드를 찾는 방법

Ruby에 모든 aliased 메소드의 '마스터' 목록이 있다면 좋지 않을까요?

소원성취!

여기를 살펴보세요 :

class Module
  def aliased_methods
    instance_methods(false)
      .group_by { |m| instance_method(m) }
      .map(&:last)
      .keep_if { |symbols| symbols.length > 1 }
  end
end

Stackoverflow 답변에서 이 코드를 얻었습니다. aliased_methods를 정의합니다. Module의 메소드 instance_methods를 사용하는 클래스 클래스에 정의된 모든 인스턴스 메서드 목록을 가져오는 메서드입니다.

다소 혼란스럽게 들릴 수도 있지만, 이것은 메타프로그래밍입니다!

다음은 코드의 나머지 부분으로, 최소한 하나의 '살아있는' 객체가 있는 모든 클래스 이름의 배열을 만든 다음 aliased_methods를 호출합니다. 모든 클래스에서 및 출력을 인쇄합니다.

objects = ObjectSpace.each_object.map(&:class).uniq

objects.each do |klass|
   methods = "n#{klass}n#{'-'*20}n"

   klass.send(:aliased_methods).each do |m1, m2|
     methods << "#{m1.to_s.ljust(15)} #{m2}n"
   end

   puts methods
end

출력은 다음과 같습니다. :

Array
--------------------
inspect         to_s
[]              slice
length          size
find_index      index
collect         map
collect!        map!

결론

ObjectSpace로 할 수 있는 멋진 작업에 대해 즐겁게 배우셨기를 바랍니다. , 지금 가서 사용해 보고 흥미로운 점을 찾으면 알려주세요!

이 게시물을 모든 프로그래머 친구들과 공유하는 것을 잊지 마세요. 그들이 새로운 것을 배우는 데 도움이 되고 더 많은 독자를 확보하는 데 도움이 될 것입니다 🙂