2011-01-26 21 views
5

Trong chương trình của tôi được viết bằng C và C++, tôi sẽ mới một đối tượng để hoàn thành nhiệm vụ, sau đó xóa đối tượng.Làm thế nào để tránh rò rỉ bộ nhớ khi người dùng nhấn ctrl + c trong linux?

Tại thời điểm sau khi đối tượng mới nhưng trước khi đối tượng xóa, nếu người dùng nhấn ctrl +c để phá vỡ quá trình này, mà sẽ gây delete không được gọi và một rò rỉ bộ nhớ xảy ra.

Tôi nên làm gì để tránh tình trạng này?

Ngoài ra, nếu bộ nhớ đã được hệ điều hành xác nhận lại, điều gì về các tệp đã mở? Chúng có bị đóng bởi hệ điều hành hay tôi nên đóng chúng bằng tay?

+0

ai đó có thể vui lòng s/Linux/Unix/để khái quát hóa điều này? –

Trả lời

7

Trong hệ thống dựa trên bộ nhớ ảo, tất cả bộ nhớ được trả về hệ điều hành khi quá trình chấm dứt, bất kể nó được giải phóng một cách rõ ràng trong mã ứng dụng hay không. Tuy nhiên, điều này có thể không đúng với các tài nguyên khác mà bạn có thể muốn miễn phí một cách sạch sẽ. Trong trường hợp đó, bạn cần cung cấp trình xử lý tín hiệu tùy chỉnh cho tín hiệu SIGINT (được nhận trên Ctrl + C), xem ví dụ: http://linux.die.net/man/2/sigaction.

+0

Điều đó có nghĩa là tôi không nên quan tâm đến bộ nhớ được phân bổ? Nhưng tôi thấy rằng destructor của tôi đã không được gọi. Ngoài ra các tập tin mở đã được đóng cửa bởi hệ điều hành? – PDF1001

+0

@ PDF1001- Ngay cả khi hệ điều hành thực hiện một số công việc cho bạn, bạn luôn nên tự dọn dẹp sau khi mình càng nhiều càng tốt. Hệ điều hành sẽ không gọi hàm hủy của bạn, nó sẽ trực tiếp giải phóng tất cả bộ nhớ mà chương trình của bạn đã cấp phát. Nếu tôi nhớ chính xác, bạn sẽ tự mình làm việc khi nói đến xử lý tệp. Khi nghi ngờ, hãy chơi nó an toàn và không cho rằng hệ điều hành sẽ làm bất cứ điều gì. – bta

1

Hệ điều hành sẽ lấy lại bộ nhớ được cấp phát bởi quy trình khi quá trình thoát là kết quả của Ctrl-C hoặc bất kỳ phương tiện nào khác.

7

Nhấn Ctrl C sẽ gửi một SIGINT đến quá trình, mà theo mặc định không ngừng hoạt động chủ yếu-trật tự, bao gồm chảy nước mắt xuống người quản lý bộ nhớ và giải phóng tất cả đống phân bổ và ngăn xếp. Nếu bạn cần thực hiện các tác vụ khác thì bạn sẽ cần phải cài đặt trình xử lý SIGINT và tự mình thực hiện các tác vụ đó.

2

Khi CTRL + C được nhấn trong bảng điều khiển Linux, tín hiệu SIGINT được gửi đến ứng dụng, nếu tín hiệu không có trình xử lý, sẽ chấm dứt chương trình, trả về tất cả bộ nhớ cho hệ điều hành. Điều này tất nhiên sẽ làm cho nó vô nghĩa để làm bất kỳ giải phóng bộ nhớ, vì tất cả bộ nhớ sẽ giải phóng một khi chương trình tồn tại. Tuy nhiên, nếu bạn muốn xử lý tín hiệu CTRL + C SIGINT (có thể ghi ra một số dữ liệu cuối cùng vào một tập tin hoặc thực hiện một số dọn dẹp khác), bạn có thể sử dụng chức năng signal() để cài đặt chức năng được gọi khi nhận được tín hiệu . Xem trang hướng dẫn sử dụng chức năng này nếu bạn muốn tìm hiểu thêm.

2

Nếu bạn đã phân bổ bất kỳ Phân đoạn bộ nhớ chia sẻ SYSV nào bằng cách sử dụng shmget(2) thì bạn phải tự dọn dẹp sau bản thân với shmctl(2).

Nếu bạn đã phân bổ bất kỳ Phân đoạn bộ nhớ chia sẻ POSIX nào bằng cách sử dụng shm_open(3) thì bạn phải tự dọn dẹp sau khi mình với shm_unlink(3).

Cả phân đoạn bộ nhớ chia sẻ SYSV và POSIX vẫn tồn tại trong quá trình chấm dứt quá trình. Bạn có thể xem những gì vẫn tồn tại bằng cách sử dụng công cụ ipcs(1).

Tất nhiên, nếu bạn chưa sử dụng bất kỳ phân đoạn bộ nhớ chia sẻ SYSV hoặc POSIX nào, thì đây chỉ là tiếng ồn. :)

2

Nếu quá trình thoát, rò rỉ bộ nhớ sẽ KHÔNG bình thường xảy ra.

Hầu hết bộ nhớ bạn phân bổ sẽ được giải phóng trên Ctrl + C. Nếu bạn thấy việc sử dụng bộ nhớ không trở về mức trước đó, nó gần như chắc chắn gây ra bởi các khối hệ thống tập tin đệm.

Tuy nhiên, bạn nên điều chắc chắn sạch lên, đặc biệt là nếu bạn đã sử dụng bất kỳ loại tài nguyên:

  • tập tin được tạo ra trong thư mục tạm thời sẽ không bị xóa. Điều này bao gồm/dev/shm, để lại một tập tin như vậy có thể được coi là một "rò rỉ bộ nhớ".
  • Các phân đoạn bộ nhớ chia sẻ V hoặc posix hệ thống sẽ không bị vứt bỏ khi quá trình của bạn thoát. Nếu điều này làm phiền bạn, hãy làm sạch chúng một cách cụ thể. Ngoài ra, làm sạch chúng trên một lần chạy tiếp theo.

Thông thường, rò rỉ (của đối tượng liên tục hoặc nửa liên tục, ví dụ: tệp) không quan trọng nếu lần chạy tiếp theo không bị rò rỉ bộ nhớ khác. Vì vậy, làm sạch trên một chạy trong tương lai là đủ tốt.

Hãy tưởng tượng một quy trình chạy cứ sau 5 phút từ "cron", nếu nó gặp sự cố trên mỗi lần chạy và để lại một số mớ hỗn độn, nó vẫn được cung cấp cho mỗi lần dọn dẹp.

0

Bạn đang đăng ký một quan niệm sai lầm phổ biến rằng các khối heap không được giải phóng, nhưng vẫn có thể truy cập tại thời điểm chương trình tồn tại là rò rỉ. Đây không phải là sự thật. Các khối bị rò rỉ là những khối không có con trỏ vẫn tham chiếu, do đó chúng không thể được giải phóng. Thông qua nhiều năm chơi với (và phá vỡ) rất nhiều hạt nhân hoàn hảo tốt, tôi chưa bao giờ quản lý đủ để phá vỡ một trình quản lý bộ nhớ ảo đến mức nó không còn khai hoang toàn bộ không gian địa chỉ của một quá trình khi nó thoát ra. Trừ khi bạn đang làm việc với một hạt nhân được đánh dấu rõ ràng là 'mới và thử nghiệm', bạn sẽ có may mắn trúng xổ số hơn là tìm một hệ thống không sử dụng trình quản lý bộ nhớ ảo hiệu quả.

Không đặt cruft trong mã của bạn chỉ để có được điểm số hoàn hảo trong Valgrind. Nếu bạn không có công việc dọn dẹp thực sự nào để làm khác hơn là giải phóng bộ nhớ vẫn có tham chiếu hợp lệ, bạn không cần phải bận tâm. Nếu ai đó ném kill -9 vào chương trình của bạn, bạn sẽ không thể xử lý nó và sẽ thấy hành vi cũ lặp lại.

Nếu bạn có các bộ mô tả tệp cần dọn dẹp, các khóa được chia sẻ để từ bỏ, các luồng để tuôn ra hoặc bất kỳ điều gì khác phải xảy ra để các quá trình khác không bỏ lỡ bạn khi bạn mất hết. Chỉ cần không đi thêm mã mà không có gì để giải quyết một vấn đề không, nó chỉ có vẻ ngớ ngẩn để làm như vậy.

Note

này ban đầu sẽ là một bình luận, nhưng là quá dài và SO cau mày trên viết một cuốn tiểu thuyết một bình luận tại một thời điểm.

Các vấn đề liên quan