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 🙂