Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เกิดอะไรขึ้นในแอปพลิเคชัน My Ruby?

หากคุณสงสัยว่าเกิดอะไรขึ้นกับแอปพลิเคชัน Ruby ของคุณ…

ไม่มีเครื่องมือ GUI แฟนซี

แต่เรามีโมดูล ObjectSpace!

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

ได้รับความปรารถนา!

ดูสิ่งนี้ :

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 เมธอดเพื่อรับรายการเมธอดอินสแตนซ์ทั้งหมดที่กำหนดไว้ในคลาส

ฉันรู้ว่าอาจฟังดูสับสนเล็กน้อย แต่นั่นเป็นเมตาโปรแกรมเมอร์สำหรับคุณ!

นี่คือโค้ดที่เหลือซึ่งสร้างอาร์เรย์ของชื่อคลาสทั้งหมดที่มีอ็อบเจ็กต์ 'alive' อย่างน้อยหนึ่งรายการ จากนั้นจะเรียก 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 ไปลองใช้ดูและแจ้งให้เราทราบหากคุณพบสิ่งที่น่าสนใจ!

อย่าลืมแชร์โพสต์นี้กับเพื่อนโปรแกรมเมอร์ของคุณทุกคน มันจะช่วยให้พวกเขาได้เรียนรู้สิ่งใหม่ &มันจะช่วยให้ฉันได้รับผู้อ่านมากขึ้น 🙂