Trình gỡ lỗi là gì và làm thế nào nó có thể giúp tôi chẩn đoán sự cố?


102

Đây là một câu hỏi có mục đích chung để hỗ trợ các lập trình viên mới gặp sự cố với chương trình, nhưng không biết cách sử dụng trình gỡ lỗi để chẩn đoán nguyên nhân của sự cố.

Câu hỏi này bao gồm ba lớp câu hỏi cụ thể hơn:

  • Khi tôi chạy chương trình của mình, nó không tạo ra đầu ra mà tôi mong đợi cho đầu vào mà tôi đã đưa.
  • Khi tôi chạy chương trình của mình, nó bị treo và cho tôi một dấu vết ngăn xếp. Tôi đã kiểm tra dấu vết ngăn xếp , nhưng tôi vẫn không biết nguyên nhân của sự cố vì dấu vết ngăn xếp không cung cấp cho tôi đủ thông tin.
  • Khi tôi chạy chương trình của mình, chương trình bị treo do lỗi phân đoạn (SEGV).

3
Làm tốt lắm - cũng sẽ rất tốt nếu bạn có câu hỏi và đáp liên quan "đến" để biết các kỹ thuật gỡ lỗi , ví dụ: sử dụng trình gỡ lỗi, các công cụ gỡ lỗi khác (ví dụ: valgrind), các bản in chiến lược, kiểm tra căng thẳng, phân chia và chinh phục, v.v.
Paul R

1
Tôi đồng ý với @PaulR, Câu hỏi thường gặp nên chứa những thứ như thế này.
Nicu Stiurca

Câu trả lời:


66

Trình gỡ lỗi là một chương trình có thể kiểm tra trạng thái chương trình của bạn trong khi chương trình của bạn đang chạy. Các phương tiện kỹ thuật mà nó sử dụng để thực hiện việc này không quan trọng đối với việc hiểu những điều cơ bản về cách sử dụng trình gỡ lỗi. Bạn có thể sử dụng trình gỡ lỗi để tạm dừng việc thực thi chương trình của mình khi chương trình đến một vị trí cụ thể trong mã của bạn, sau đó kiểm tra giá trị của các biến trong chương trình. Bạn có thể sử dụng trình gỡ lỗi để chạy chương trình của mình rất chậm, một dòng mã tại một thời điểm (được gọi là bước đơn ), trong khi bạn kiểm tra các giá trị của các biến của nó.

Sử dụng trình gỡ lỗi là một kỹ năng cơ bản được mong đợi

Trình gỡ lỗi là một công cụ rất mạnh để giúp chẩn đoán sự cố với chương trình. Và trình gỡ lỗi có sẵn cho tất cả các ngôn ngữ lập trình thực tế. Do đó, có thể sử dụng trình gỡ lỗi được coi là một kỹ năng cơ bản của bất kỳ lập trình viên chuyên nghiệp hoặc đam mê nào. Và việc tự mình sử dụng một trình gỡ lỗi được coi là công việc cơ bản bạn nên tự làm trước khi nhờ người khác giúp đỡ. Vì trang web này dành cho các lập trình viên chuyên nghiệp và đam mê, không phải là trang web hỗ trợ hoặc cố vấn, nếu bạn có câu hỏi về sự cố với một chương trình cụ thể, nhưng chưa sử dụng trình gỡ lỗi, câu hỏi của bạn rất có thể bị đóng và bị loại bỏ. Nếu bạn vẫn tiếp tục với những câu hỏi như vậy, cuối cùng bạn sẽ bị chặn đăng thêm.

Trình gỡ lỗi có thể giúp bạn như thế nào

Bằng cách sử dụng trình gỡ lỗi, bạn có thể phát hiện ra liệu một biến có giá trị sai hay không và giá trị của nó bị thay đổi thành giá trị sai ở đâu trong chương trình của bạn.

Sử dụng một bước duy nhất, bạn cũng có thể khám phá liệu luồng điều khiển có như bạn mong đợi hay không. Ví dụ, liệu một ifnhánh có được thực thi khi bạn mong đợi hay không.

Lưu ý chung về việc sử dụng trình gỡ lỗi

Các chi tiết cụ thể của việc sử dụng trình gỡ lỗi phụ thuộc vào trình gỡ lỗi và ở mức độ thấp hơn, ngôn ngữ lập trình bạn đang sử dụng.

  • Bạn có thể đính kèm trình gỡ lỗi vào một quy trình đã chạy chương trình của bạn. Bạn có thể làm nếu chương trình của bạn bị kẹt.

  • Trong thực tế, việc chạy chương trình của bạn dưới sự điều khiển của trình gỡ lỗi thường dễ dàng hơn ngay từ đầu.

  • Bạn chỉ ra nơi chương trình của bạn sẽ dừng thực thi bằng cách chỉ ra tệp mã nguồn và số dòng của dòng mà tại đó việc thực thi sẽ dừng hoặc bằng cách chỉ ra tên của phương thức / chức năng mà tại đó chương trình sẽ dừng lại (nếu bạn muốn dừng lại ngay sau khi thực thi vào phương thức). Phương tiện kỹ thuật mà trình gỡ lỗi sử dụng để khiến chương trình của bạn dừng được gọi là điểm ngắt và quá trình này được gọi là thiết lập điểm ngắt .

  • Hầu hết các trình gỡ lỗi hiện đại là một phần của IDE và cung cấp cho bạn GUI thuận tiện để kiểm tra mã nguồn và các biến của chương trình của bạn, với giao diện trỏ và nhấp để thiết lập các điểm ngắt, chạy chương trình của bạn và chỉ một bước.

  • Việc sử dụng trình gỡ lỗi có thể rất khó trừ khi các tệp thực thi chương trình hoặc tệp bytecode của bạn bao gồm thông tin ký hiệu gỡ lỗi và các tham chiếu chéo đến mã nguồn của bạn. Bạn có thể phải biên dịch (hoặc biên dịch lại) chương trình của mình hơi khác một chút để đảm bảo rằng thông tin có sẵn. Nếu trình biên dịch thực hiện tối ưu hóa rộng rãi, các tham chiếu chéo đó có thể trở nên khó hiểu. Do đó, bạn có thể phải biên dịch lại chương trình của mình khi tắt tối ưu hóa .


4
Điều này chưa hoàn chỉnh vì nó bỏ sót trình gỡ lỗi quan trọng nhất, một trình gỡ lỗi có khả năng giảm số lượng câu hỏi trên Stackoverflow rất đáng kể (tôi dự đoán ít nhất là 20%) - trình gỡ lỗi javascript: firebug, Chrome, Firefox, IE9 + trình gỡ lỗi tích hợp , IE8- Visual Studio, v.v.
slbetman,

1
Cũng đối với node.js - trình kiểm tra nút. Nhưng các lập trình viên node.js không hỏi nhiều câu hỏi cơ bản và / hoặc fix-my-code như các lập trình viên javascript thông thường.
slbetman

39

Tôi muốn nói thêm rằng trình gỡ lỗi không phải lúc nào cũng là giải pháp hoàn hảo và không phải lúc nào cũng là giải pháp phù hợp để gỡ lỗi. Dưới đây là một số trường hợp trình gỡ lỗi có thể không hoạt động với bạn:

  • Phần chương trình của bạn bị lỗi thực sự rất lớn (có thể là mô-đun hóa kém?) Và bạn không chắc chắn chính xác nơi bắt đầu bước qua mã. Bước qua tất cả các bước có thể quá tốn thời gian.
  • Chương trình của bạn sử dụng rất nhiều lệnh gọi lại và các phương pháp điều khiển luồng phi tuyến tính khác, điều này làm cho trình gỡ lỗi bị nhầm lẫn khi bạn bước qua nó.
  • Chương trình của bạn là đa luồng. Hoặc thậm chí tệ hơn, vấn đề của bạn là do tình trạng chủng tộc.
  • Mã có lỗi sẽ chạy nhiều lần trước khi lỗi. Điều này có thể đặc biệt có vấn đề trong các vòng lặp chính, hoặc tệ hơn là trong các động cơ vật lý, nơi mà vấn đề có thể là số. Ngay cả việc thiết lập một điểm ngắt, trong trường hợp này, đơn giản là bạn sẽ đánh nó nhiều lần, với lỗi không xuất hiện.
  • Chương trình của bạn phải chạy trong thời gian thực. Đây là một vấn đề lớn đối với các chương trình kết nối với mạng. Nếu bạn thiết lập một điểm ngắt trong mã mạng của mình, đầu kia sẽ không đợi bạn bước qua mà chỉ đơn giản là hết thời gian. Các chương trình dựa vào đồng hồ hệ thống, ví dụ như trò chơi với khung hình, cũng không tốt hơn nhiều.
  • Chương trình của bạn thực hiện một số dạng hành động phá hoại, chẳng hạn như ghi vào tệp hoặc gửi e-mail và bạn muốn giới hạn số lần bạn cần chạy qua nó.
  • Bạn có thể nói rằng lỗi của bạn là do các giá trị đến hàm X không chính xác, nhưng bạn không biết các giá trị này đến từ đâu. Việc phải chạy đi chạy lại chương trình, đặt các điểm ngắt ngày càng xa, có thể là một rắc rối lớn. Đặc biệt nếu hàm X được gọi từ nhiều nơi trong suốt chương trình.

Trong tất cả các trường hợp này, việc chương trình của bạn dừng đột ngột có thể khiến kết quả cuối cùng khác nhau hoặc thực hiện theo cách thủ công để tìm kiếm một dòng mà lỗi gây ra quá phức tạp. Điều này có thể xảy ra như nhau cho dù lỗi của bạn là hành vi không chính xác hoặc sự cố. Ví dụ: nếu hỏng bộ nhớ gây ra sự cố, vào thời điểm sự cố xảy ra, nó quá xa so với nơi xảy ra lỗi bộ nhớ đầu tiên và không còn thông tin hữu ích nào.

Vì vậy, các lựa chọn thay thế là gì?

Đơn giản nhất chỉ đơn giản là ghi nhật ký và xác nhận. Thêm nhật ký vào chương trình của bạn ở nhiều điểm khác nhau và so sánh những gì bạn nhận được với những gì bạn đang mong đợi. Ví dụ, hãy xem liệu chức năng mà bạn cho rằng có lỗi có được gọi ngay từ đầu hay không. Xem liệu các biến ở đầu một phương pháp có đúng như bạn nghĩ không. Không giống như các điểm ngắt, không sao cả khi có nhiều dòng nhật ký trong đó không có gì đặc biệt xảy ra. Bạn có thể chỉ cần tìm kiếm thông qua nhật ký sau đó. Khi bạn đạt đến một dòng nhật ký khác với những gì bạn đang mong đợi, hãy thêm nhiều dòng khác vào cùng một khu vực. Thu hẹp nó ngày càng xa, cho đến khi nó đủ nhỏ để có thể ghi lại mọi dòng trong khu vực bị nghe trộm.

Các xác nhận có thể được sử dụng để bẫy các giá trị không chính xác khi chúng xảy ra, thay vì một khi chúng có tác dụng hiển thị cho người dùng cuối. Bạn bắt được một giá trị không chính xác càng nhanh, bạn càng gần với dòng tạo ra nó.

Refactor và kiểm thử đơn vị. Nếu chương trình của bạn quá lớn, bạn nên kiểm tra một lớp hoặc một hàm tại một thời điểm. Cung cấp cho nó đầu vào, và xem xét đầu ra, và xem cái nào không như bạn mong đợi. Khả năng thu hẹp một lỗi từ toàn bộ chương trình thành một chức năng duy nhất có thể tạo ra sự khác biệt lớn về thời gian gỡ lỗi.

Trong trường hợp bộ nhớ bị rò rỉ hoặc bộ nhớ ngừng hoạt động, hãy sử dụng các công cụ thích hợp có khả năng phân tích và phát hiện chúng trong thời gian chạy. Bước đầu tiên có thể phát hiện ra nơi tham nhũng thực sự xảy ra. Sau đó, bạn có thể sử dụng nhật ký để quay lại nơi các giá trị không chính xác được đưa vào.

Hãy nhớ rằng gỡ lỗi là một quá trình đi ngược lại. Bạn có kết quả cuối cùng - một lỗi - và tìm nguyên nhân, dẫn đến nó. Đó là làm việc theo cách của bạn lùi lại và, thật không may, trình gỡ lỗi chỉ bước về phía trước. Đây là nơi mà việc ghi nhật ký tốt và phân tích sau khám nghiệm có thể cho bạn kết quả tốt hơn nhiều.


10
Đây sẽ là một câu trả lời tốt ... cho một câu hỏi khác. Đó là một câu trả lời tồi cho câu hỏi này . Có lẽ bạn nên đặt câu hỏi đó và đăng bài này như một câu trả lời cho nó.
Raedwald

7
Câu hỏi thực tế được mô tả là "hỗ trợ các lập trình viên mới gặp sự cố với chương trình", "chương trình không tạo ra kết quả như tôi mong đợi" và "Tôi đã kiểm tra dấu vết ngăn xếp, nhưng tôi vẫn không biết nguyên nhân của sự cố" . Tất cả đều được hỗ trợ bởi câu trả lời này. Ngoài ra, khi giải thích những gì trình gỡ lỗi làm, điều quan trọng không kém là giải thích những gì nó không làm.
SlugFiller

5
Câu trả lời chính xác. Tôi luôn sử dụng trình gỡ lỗi làm công cụ chính để tìm lỗi. Nhưng bây giờ tôi đang làm việc trong một dự án mà một thành phần cơ sở hạ tầng khổng lồ đang sử dụng nhiều luồng và nhiều mã mạng (máy khách / máy chủ) và nhận thấy rằng trình gỡ lỗi là thứ cuối cùng giúp tôi. Bạn đã đề cập đến rất nhiều điều mà bạn thực sự nên sử dụng một công cụ khác thay vì dựa vào trình gỡ lỗi cũ tốt của mình (quan trọng nhất: ghi nhật ký).
Tim Schmelter

"Bạn có thể nói rằng lỗi của bạn là do các giá trị đến hàm X không chính xác nhưng bạn không biết các giá trị này đến từ đâu" Điều này đặc biệt khó gỡ lỗi. Làm thế nào để bạn thường đi sửa một cái gì đó như vậy?
Ayxan Haqverdili

2
@Ayxan Ở một mức độ nào đó, nếu bạn đã quản lý để làm cho hàm ngắt trên một xác nhận, bạn có thể sử dụng ngăn xếp cuộc gọi để nhận được trình gọi. Nhưng chỉ điều đó không cung cấp cho bạn nguồn của giá trị, vì giá trị rất có thể là từ một dòng trước đó. Về cơ bản, bạn phải theo dõi giá trị trở lại, thông qua các biến khác nhau mà nó đi qua. Nếu bạn biết rõ về đường đi của dữ liệu, bạn có thể chỉ cần tạo một loạt các bản in nhật ký và cố gắng thu hẹp nơi nó "sai". Nếu không, về cơ bản bạn sẽ cần một lần chạy chương trình riêng biệt (tái tạo lỗi) cho mỗi bước quay lại.
SlugFiller
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.