Computer >> Máy Tính >  >> Lập trình >> Ruby

Điều gì đang xảy ra trong ứng dụng Ruby của tôi?

Nếu bạn đang tự hỏi điều gì đang xảy ra với ứng dụng Ruby của mình…

Không có không có công cụ GUI ưa thích nào

Nhưng chúng ta có mô-đun ObjectSpace!

Không gian đối tượng cung cấp cho bạn thông tin về trạng thái hiện tại của ứng dụng của bạn.

Hãy khám phá cách hoạt động của nó.

Đếm đối tượng

Sử dụng ObjectSpace bạn có thể biết những đối tượng nào hiện đang "tồn tại" trong chương trình của bạn.

Đối với một vật thể sống có nghĩa là gì?

Một đối tượng tồn tại miễn là nó có bất kỳ tham chiếu nào trỏ đến nó. Tham chiếu chỉ là một cách để truy cập đối tượng, như một biến hoặc một hằng số.

Nếu không thể tiếp cận một đối tượng thì điều đó có nghĩa là nó sẽ an toàn được xóa khỏi bộ nhớ.

Ví dụ :

# 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'

Bây giờ chúng ta hãy xem một ví dụ về ObjectSpace đang hoạt động:

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}" }

Thao tác này sẽ in ra một bảng với số lượng đối tượng cho 10 lớp hàng đầu của bạn.

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

Nếu bạn nghi ngờ bị rò rỉ bộ nhớ, bạn có thể ghi lại dữ liệu này mỗi giờ và tìm hiểu xem có một số đối tượng liên tục tăng nhưng không bao giờ giảm xuống.

Vui vẻ với đồ vật

Khi sử dụng ObjectSpace bạn có quyền truy cập vào các đối tượng thực tế, không chỉ thông tin về chúng, vì vậy bạn có thể thực hiện một số việc thú vị như in giá trị của tất cả các chuỗi hoặc in đường dẫn của tất cả File của bạn đối tượng.

Ví dụ :

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

Thao tác này sẽ in tất cả các chuỗi trong bộ nhớ, được sắp xếp theo kích thước. Bạn sẽ nhận thấy rằng có nhiều chuỗi mà bạn không tự tạo, chúng được tạo bởi trình thông dịch Ruby.

Công dụng thực tế?

Chà, đây chủ yếu là để gỡ lỗi và thu thập số liệu thống kê về ứng dụng của bạn 🙂

Kích thước bộ nhớ đối tượng

Một điều khác bạn có thể làm là sử dụng ObjectSpace.memsize_of để tìm kích thước bộ nhớ của một đối tượng cụ thể.

Ví dụ :

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

Một điều cần ghi nhớ là cảnh báo này từ tài liệu:

“Lưu ý rằng kích thước trả về là không đầy đủ. Bạn chỉ cần xử lý thông tin này như một GỢI Ý. ”

Nếu bạn thử phương pháp này với các loại đối tượng khác nhau bạn sẽ thấy một số điều thú vị , như Fixnum s luôn trả về 0.

ObjectSpace.memsize_of(42)
# 0

Lý do cho điều này là Ruby không tạo nội bộ Fixnum các đối tượng, bạn có thể tìm hiểu thêm về điều này trong bài đăng tôi đã viết về các số trong Ruby.

Một điều thú vị khác là các chuỗi:

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

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

ObjectSpace.memsize_of("A" * 24)
# 65

Tôi sử dụng "A" * size như một cách để tạo một chuỗi dài hơn mà không cần phải gõ ra 🙂

Chờ đợi! Điều gì vừa xảy ra?

Chà, hóa ra Ruby có một tính năng tối ưu hóa tích hợp cho các chuỗi nhỏ hơn 24 ký tự, đó là lý do tại sao việc sử dụng bộ nhớ tăng vọt sau đó. Bạn có thể xem điều này chi tiết hơn trong bài đăng này của Pat Shaughnessy.

Cách tìm các phương pháp có bí danh

Sẽ thật tuyệt nếu có một danh sách 'chính' của tất cả các phương thức bí danh trong Ruby phải không?

Điều ước được thành công!

Hãy xem cái này :

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

Tôi nhận được mã này từ câu trả lời Stackoverflow. Nó định nghĩa một aliased_methods trên Module lớp sử dụng instance_methods để lấy danh sách tất cả các phương thức phiên bản được định nghĩa trên một lớp.

Tôi biết điều đó nghe có vẻ hơi khó hiểu, nhưng đó là cách lập trình ẩn dành cho bạn!

Đây là phần còn lại của đoạn mã, nó xây dựng một mảng gồm tất cả các tên lớp có ít nhất một đối tượng "còn sống", sau đó nó gọi aliased_methods trên mọi lớp và in đầu ra.

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

Đây là kết quả đầu ra trông như thế nào :

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

Kết luận

Tôi hy vọng bạn thích học về những điều thú vị mà bạn có thể làm với ObjectSpace , bây giờ hãy dùng thử và cho tôi biết nếu bạn thấy bất kỳ điều gì thú vị!

Đừng quên chia sẻ bài đăng này với tất cả bạn bè lập trình viên của bạn, nó sẽ giúp họ học được điều gì đó mới và nó sẽ giúp tôi có nhiều độc giả hơn 🙂