Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Profiling phân bổ bộ nhớ Ruby với Google TCMalloc

Phân bổ bộ nhớ trong Ruby hoạt động như thế nào?

Ruby lấy bộ nhớ theo từng khối, gọi là pages (trang), đối tượng mới được lưu ở đây.

Sau đó…

Khi các trang này đầy, cần thêm bộ nhớ.

Ruby yêu cầu thêm bộ nhớ từ hệ điều hành với hàm malloc.

Hàm malloc này là một phần của chính hệ điều hành, nhưng có các triển khai thay thế bạn có thể dùng.

Một trong những triển khai đó là tcmalloc của Google.

TCmalloc là một phần của bộ công cụ Google Performance Tools.

Bạn có thể dùng các công cụ này để khám phá chính xác Ruby phân bổ bộ nhớ như thế nào.

Và nhờ biến môi trường LD_PRELOAD (trên Linux) chúng ta có thể thay thế hàm malloc của hệ thống bằng tcmalloc.

Như sau:

LD_PRELOAD="/usr/lib/libtcmalloc.so" ruby -e "puts 123"

Nhưng điều đó chỉ tải thư viện, chưa bật thu thập dữ liệu.

Hãy xem cách làm điều đó.

Bật Profiler

Bạn có thể bật profiler của tcmalloc với biến môi trường thêm (HEAPPROFILE).

LD_PRELOAD="/usr/lib/libtcmalloc.so" HEAPPROFILE=/tmp/profile ruby -e "puts 123"

Điều này sẽ tạo ra đầu ra sau:

Starting tracking the heap
123
Dumping heap profile to /tmp/profile.0001.heap (Exiting, 2 MB in use)

Ở đây bạn thấy xác nhận profiler đã được bật.

Sau đó chúng ta thấy:

  • Đầu ra của chương trình
  • Tên file (profile.0001.heap)
  • Lượng bộ nhớ được dùng bởi chương trình (2 MB)

Để đọc file này bạn sẽ cần công cụ khác đi kèm tcmalloc.

pprof --text `which ruby` /tmp/profile.0001.heap | head -10

Điều này sẽ tạo ra đầu ra sau:

Total: 2.4 MB
1.1 44.7% 44.7% 1.1 44.7% 0x00005570fa4df074
0.7 27.8% 72.5% 0.7 27.8% 0x00005570fa4e0c09
0.4 15.3% 87.8% 0.4 15.3% 0x00005570fa4db460
0.1 5.9% 93.7% 0.1 5.9% 0x00005570fa4df19f
0.1 3.2% 96.9% 0.1 3.2% 0x00005570fa6349a0
0.0 1.4% 98.3% 0.0 1.4% 0x00005570fa589924
0.0 0.3% 98.6% 0.0 0.3% 0x00005570fa59c4f2
0.0 0.3% 98.8% 0.0 0.3% 0x00005570fa4db48a
0.0 0.2% 99.0% 0.0 0.2% 0x00005570fa4dbaa5
0.0 0.2% 99.1% 0.0 0.2% _dl_new_object

Vâng, đó chỉ là một đống địa chỉ bộ nhớ! Bạn cần phiên bản Ruby có debugging symbols để có thể thấy tên hàm.

Khi đó bạn sẽ nhận được đầu ra này:

Using local file ruby. Using local file /tmp/profile.0001.heap.
Total: 2.9 MB
1.0 36.2% 36.2% 1.0 36.2% objspace_xmalloc0
0.7 26.1% 62.4% 0.7 26.1% aligned_malloc
0.5 18.8% 81.1% 0.5 18.8% objspace_xcalloc
0.3 9.9% 91.0% 0.3 9.9% stack_chunk_alloc
0.1 3.7% 94.7% 0.1 3.7% objspace_xrealloc
0.1 2.7% 97.4% 0.1 2.7% Init_Method
0.0 1.3% 98.7% 0.0 1.7% onig_new_with_source
0.0 0.4% 99.2% 0.8 26.6% heap_page_allocate
0.0 0.2% 99.4% 0.0 0.2% add_bitset

Điều bạn thấy ở đây là lượng bộ nhớ được phân bổ bởi các hàm của MRI.

Thú vị là aligned_malloc là hàm dùng để phân bổ trang mới cho đối tượng Ruby, stack_chunk_alloc được GC dùng trong giai đoạn marking, và objspace_xmalloc0 / objspace_xcalloc phân bổ không gian cho chuỗi, mảng & bất kỳ dữ liệu nào không vừa trong struct RVALUE.

Bây giờ:

TCmalloc không biết gì về đối tượng Ruby, nó chỉ theo dõi các cuộc gọi malloc, calloc & realloc để biết bao nhiêu bộ nhớ được yêu cầu.

Nếu bạn muốn heap dump ở cấp độ Ruby bạn có thể dùng ObjectSpace.dump_all. Điều này cho bạn file JSON với tất cả đối tượng sống trong ứng dụng & kích thước bộ nhớ của chúng.

Nhưng tcmalloc có thể cho bạn thấy trực quan hóa tất cả các hàm C kết thúc bằng việc yêu cầu bộ nhớ.

pprof --web `which ruby` /tmp/profile.0001.heap

Điều này sẽ mở Chrome hoặc Firefox với file SVG trông như thế này:

Profiling phân bổ bộ nhớ Ruby với Google TCMalloc

Không chỉ TCmalloc cho bạn khả năng profiling đẹp mắt, dùng nó bạn cũng có thể tăng hiệu suất ứng dụng 4-9%! Bạn cũng có thể thử jemalloc, một triển khai malloc khác cũng bao gồm profiler.

Tóm tắt

Bạn đã học cách dùng gperftools (Google Performance Tools) để trực quan hóa & phân tích việc sử dụng bộ nhớ của trình thông dịch Ruby.

Cảm ơn bạn đã đọc! 🙂