Rò rỉ bộ nhớ bao giờ ok? [đóng cửa]


231

Có bao giờ chấp nhận được việc rò rỉ bộ nhớ trong ứng dụng C hoặc C ++ của bạn không?

Điều gì sẽ xảy ra nếu bạn phân bổ một số bộ nhớ và sử dụng nó cho đến dòng mã cuối cùng trong ứng dụng của bạn (ví dụ: hàm hủy của đối tượng toàn cầu)? Miễn là mức tiêu thụ bộ nhớ không tăng theo thời gian, bạn có thể tin tưởng HĐH sẽ giải phóng bộ nhớ cho bạn khi ứng dụng của bạn chấm dứt (trên Windows, Mac và Linux) không? Bạn thậm chí có thể coi đây là một rò rỉ bộ nhớ thực nếu bộ nhớ được sử dụng liên tục cho đến khi nó được hệ điều hành giải phóng.

Điều gì nếu một thư viện bên thứ ba buộc tình huống này vào bạn? Sẽ từ chối sử dụng thư viện của bên thứ ba cho dù nó có tuyệt vời đến thế nào?

Tôi chỉ thấy một nhược điểm thực tế, và đó là những rò rỉ lành tính này sẽ hiển thị với các công cụ phát hiện rò rỉ bộ nhớ là dương tính giả.


50
Nếu mức tiêu thụ bộ nhớ không tăng theo thời gian, đó không phải là rò rỉ.
mpez0

4
Hầu hết các ứng dụng (bao gồm tất cả các chương trình .NET) có ít nhất một vài bộ đệm được phân bổ một lần và không bao giờ được giải phóng rõ ràng. Vì vậy, định nghĩa của mpez0 hữu ích hơn.
Ben Voigt

2
Có, nếu bạn có bộ nhớ vô hạn.
người dùng

Rò rỉ "lành tính" (nếu có một điều như vậy) không phải là dương tính giả - đó là một rò rỉ được phát hiện rất chính xác. Phát hiện rò rỉ, ngay cả đối với các rò rỉ mà cá nhân bạn không cảm thấy muốn sửa chữa, là toàn bộ lý do phát hiện rò rỉ.
cHao

1
@ mpez0 "Nếu mức tiêu thụ bộ nhớ không tăng theo thời gian, đó không phải là rò rỉ"? Đó không phải là định nghĩa về rò rỉ bộ nhớ. Rò rỉ là bộ nhớ đã bị rò rỉ, điều đó có nghĩa là nó không được giải phóng và bạn không còn liên quan đến nó nữa, do đó bạn không thể giải phóng nó một lần nữa. Cho dù nó phát triển hay không là không liên quan.
Mecki

Câu trả lời:


329

Không.

Là các chuyên gia, câu hỏi chúng ta không nên tự hỏi mình là "Làm như thế nào là ổn?" nhưng đúng hơn là "Có bao giờ một lý do tốt để làm điều này?" Và "săn lùng sự rò rỉ ký ức đó là một nỗi đau" không phải là một lý do chính đáng.

Tôi muốn giữ cho mọi thứ đơn giản. Và quy tắc đơn giản là chương trình của tôi không bị rò rỉ bộ nhớ.

Điều đó làm cho cuộc sống của tôi đơn giản, quá. Nếu tôi phát hiện rò rỉ bộ nhớ, tôi sẽ loại bỏ nó, thay vì chạy qua một số cấu trúc cây quyết định phức tạp để xác định xem đó có phải là rò rỉ bộ nhớ "chấp nhận được" hay không.

Nó tương tự như cảnh báo của trình biên dịch - cảnh báo có gây tử vong cho ứng dụng cụ thể của tôi không? Có thể không.

Nhưng cuối cùng đó là vấn đề kỷ luật chuyên nghiệp. Khoan dung cảnh báo trình biên dịch và dung sai rò rỉ bộ nhớ là một thói quen xấu cuối cùng sẽ cắn tôi ở phía sau.

Để đưa mọi thứ đến mức cực đoan, liệu bác sĩ phẫu thuật có thể để lại một số thiết bị hoạt động bên trong bệnh nhân không?

Mặc dù có thể xảy ra trường hợp có thể xảy ra khi chi phí / rủi ro khi tháo thiết bị đó vượt quá chi phí / rủi ro khi để nó vào, và có thể có trường hợp vô hại, nếu tôi thấy câu hỏi này được đăng trên SurgeonOverflow.com và thấy bất kỳ câu trả lời nào khác ngoài "không", nó sẽ làm suy yếu nghiêm trọng sự tự tin của tôi đối với ngành y.

-

Nếu một thư viện bên thứ ba ép buộc tình huống này đối với tôi, nó sẽ khiến tôi nghi ngờ nghiêm trọng về chất lượng chung của thư viện. Sẽ như thể tôi đã lái thử một chiếc ô tô và tìm thấy một vài vòng đệm và đai ốc lỏng lẻo trong một trong những chiếc cốc - nó có thể không phải là vấn đề lớn, nhưng nó cho thấy sự thiếu cam kết về chất lượng, vì vậy tôi sẽ xem xét các lựa chọn thay thế.


57
Đúng và không đúng cùng một lúc. Cuối cùng, hầu hết chúng ta là nô lệ tiền lương và bất kỳ mong muốn nào cho nghề thủ công phải có chỗ dựa cho các yêu cầu của doanh nghiệp. Nếu thư viện bên thứ 3 đó bị rò rỉ và tiết kiệm 2 tuần làm việc, có thể có một trường hợp kinh doanh để sử dụng nó, v.v ...
Cervo

3
Dù sao tôi cũng sẽ sử dụng thư viện, nếu đó là thứ tôi cần và không có lựa chọn thay thế nào, nhưng tôi sẽ ghi lại lỗi với những người bảo trì.
tloach

7
Mặc dù cá nhân tôi đi cùng một câu trả lời chính xác, có những chương trình hầu như không có bộ nhớ. Lý do là chúng là một) dự định chạy trên các hệ điều hành có bộ nhớ trống và b) được thiết kế để không chạy quá lâu. Các ràng buộc hiếm hoi cho một chương trình thực sự, nhưng tôi chấp nhận điều này là hoàn toàn hợp lệ.

2
Để thêm một số lý do để kiểm tra sớm: khi các công cụ gỡ lỗi của bạn tràn ngập các rò rỉ "lành tính", làm thế nào bạn sẽ tìm thấy "công cụ" thực sự? Nếu bạn thêm một tính năng hàng loạt, và đột nhiên rò rỉ 1K / giờ của bạn trở thành 1K / giây?
peterchen

5
Hmm là "không bị rò rỉ bộ nhớ" "hoàn hảo"?
JohnMcG

80

Tôi không coi đó là rò rỉ bộ nhớ trừ khi dung lượng bộ nhớ được "sử dụng" tiếp tục tăng. Có một số bộ nhớ chưa được phát hành, trong khi không lý tưởng, không phải là một vấn đề lớn trừ khi số lượng bộ nhớ cần thiết tiếp tục tăng.


12
Về mặt kỹ thuật, rò rỉ là bộ nhớ được phân bổ và tất cả các tham chiếu đến nó bị mất. Không giải quyết bộ nhớ ở cuối chỉ là lười biếng.
Martin York

17
Nếu bạn bị rò rỉ bộ nhớ 1 lần 4 GB thì đó là một vấn đề.
John Dibling

21
Không quan trọng nếu nó phát triển hay không. Các chương trình khác không thể sử dụng bộ nhớ nếu bạn đã phân bổ.
Bill Lizard

8
> Các chương trình khác không thể sử dụng bộ nhớ nếu bạn đã phân bổ. Chà, HĐH luôn có thể trao đổi bộ nhớ của bạn vào đĩa và cho phép các ứng dụng khác sử dụng RAM mà bạn không tận dụng.
Max Lybbert

4
Nếu chương trình rất ngắn, thì rò rỉ có thể không quá tệ. Ngoài ra, mặc dù KHÔNG lý tưởng, phân trang không đắt như một số người ở đây cho là như vậy, bởi vì chương trình không quan tâm đến bộ nhớ đó (Và do đó sẽ không được hoán đổi mọi lúc) - trừ khi, tất nhiên, bạn có một GC ...
Arafangion

79

Trước tiên, hãy lấy định nghĩa của chúng tôi chính xác. Rò rỉ bộ nhớ là khi bộ nhớ được cấp phát động, ví dụ như với malloc(), và tất cả các tham chiếu đến bộ nhớ bị mất mà không có miễn phí tương ứng. Một cách dễ dàng để làm cho một là như thế này:

#define BLK ((size_t)1024)
while(1){
    void * vp = malloc(BLK);
}

Lưu ý rằng mỗi lần xung quanh vòng lặp while (1), các byte 1024 (+ phí) được phân bổ và địa chỉ mới được gán cho vp; không còn con trỏ nào cho các khối malloc'ed trước đó. Chương trình này được đảm bảo chạy cho đến khi hết đống, và không có cách nào để phục hồi bất kỳ bộ nhớ nào của malloc'ed. Bộ nhớ bị "rò rỉ" ra khỏi đống, không bao giờ được nhìn thấy nữa.

Những gì bạn đang mô tả, mặc dù, nghe như

int main(){
    void * vp = malloc(LOTS);
    // Go do something useful
    return 0;
}

Bạn phân bổ bộ nhớ, làm việc với nó cho đến khi chương trình kết thúc. Đây không phải là rò rỉ bộ nhớ; nó không làm suy yếu chương trình và tất cả bộ nhớ sẽ được dọn sạch tự động khi chương trình kết thúc.

Nói chung, bạn nên tránh rò rỉ bộ nhớ. Đầu tiên, vì giống như độ cao phía trên bạn và trở lại nhà chứa máy bay, bộ nhớ bị rò rỉ và không thể phục hồi là vô ích; Thứ hai, việc mã hóa chính xác dễ dàng hơn nhiều, không bị rò rỉ bộ nhớ, khi bắt đầu so với việc tìm thấy rò rỉ bộ nhớ sau này.


Bây giờ hãy xem xét một vài chục phân bổ này. Bây giờ hãy xem xét việc phải di chuyển cơ thể "chính" thành thói quen được gọi nhiều lần. Thưởng thức. - Tôi đồng ý với tình cảm rằng đó không phải là một vấn đề lớn trong kịch bản này, nhưng kịch bản thay đổi. Như họ nói, luôn viết mã như thể anh chàng để duy trì nó biết bạn sống ở đâu.
peterchen

2
Chà, vấn đề là bộ nhớ được đặt và giữ cho đến khi chương trình gọi _exit () không bị "rò rỉ".
Charlie Martin

1
Đây là một rò rỉ bộ nhớ và nó có thể làm giảm chương trình của bạn. Phân bổ trong tương lai có thể thất bại từ quy trình này bởi vì tôi chắc chắn rằng bạn đang kiểm tra rằng malloc trở lại không có ở khắp mọi nơi. bằng cách sử dụng bộ nhớ, chẳng hạn như trong một tình huống nhúng mà bộ nhớ khan hiếm, đây có thể là sự khác biệt giữa sống và chết.
MikeJ

10
Mike, điều đó không đúng. Trong môi trường C tuân thủ, việc kết thúc chính sẽ giải phóng tất cả các tài nguyên quy trình. Trong một môi trường nhúng như bạn mô tả, bạn có thể thấy tình huống đó, nhưng bạn sẽ không có chính. Bây giờ, tôi sẽ cho rằng có thể có những môi trường nhúng bị lỗi mà điều này không đúng, nhưng sau đó tôi đã thấy những môi trường không hoàn hảo không thể đối phó với + = chính xác.
Charlie Martin

3
Vâng, bây giờ bạn đã phát hiện ra rằng nếu bạn có mallocquá nhiều bộ nhớ thì đó là một điều tồi tệ. Nó vẫn không bị rò rỉ . Nó không phải là một rò rỉ cho đến khi và trừ khi nó là mallocbộ nhớ bị mất tham chiếu.
Charlie Martin

39

Trong lý thuyết không, trong thực tế, nó phụ thuộc .

Nó thực sự phụ thuộc vào số lượng dữ liệu mà chương trình đang làm việc, tần suất chương trình được chạy và liệu nó có chạy liên tục hay không.

Nếu tôi có một chương trình nhanh chóng đọc một lượng nhỏ dữ liệu sẽ thực hiện phép tính và thoát, một rò rỉ bộ nhớ nhỏ sẽ không bao giờ được chú ý. Do chương trình không chạy quá lâu và chỉ sử dụng một lượng bộ nhớ nhỏ, nên rò rỉ sẽ nhỏ và được giải phóng khi chương trình tồn tại.

Mặt khác, nếu tôi có một chương trình xử lý hàng triệu bản ghi và chạy trong một thời gian dài, một rò rỉ bộ nhớ nhỏ có thể khiến máy mất đủ thời gian.

Đối với các thư viện bên thứ ba có rò rỉ, nếu chúng gây ra sự cố, hãy sửa thư viện hoặc tìm giải pháp thay thế tốt hơn. Nếu nó không gây ra vấn đề, nó có thực sự quan trọng không?


Tôi không biết nếu bạn đọc toàn bộ câu hỏi của tôi hay không. Tôi đang nói rằng bộ nhớ được sử dụng cho đến khi kết thúc ứng dụng. Nó không phát triển theo thời gian. Điều duy nhất không không là không có cuộc gọi để miễn phí / xóa.
Bắt đầu

2
Sau đó, nó không thực sự bị rò rỉ bộ nhớ. Rò rỉ bộ nhớ là một lượng nhỏ bộ nhớ không sử dụng nhưng không có bộ nhớ, số lượng này sẽ lớn hơn theo thời gian. Những gì bạn đang nói là một giọt bộ nhớ. Đừng quan tâm đến điều này trừ khi giọt nước của bạn rất lớn.
vfilby

"Nếu nó không gây ra vấn đề, nó có thực sự quan trọng không?" Không, nó không thành vấn đề. Tôi muốn nhiều người có được điều đó thay vì tôn giáo.
Imbue

2
@ John: Đó thường là một câu hỏi của các nhà phát triển lười biếng và nhiều hơn là một câu hỏi về phát triển phần mềm. Tất cả chúng ta đều phạm sai lầm, lỗi là giao dịch của chúng ta; chúng tôi làm cho họ chúng tôi sửa chữa chúng, đó là những gì chúng tôi làm. Đó luôn là sự cân bằng giữa chi phí trả trước và bảo trì dài hạn, sự cân bằng đó không bao giờ đơn giản.
vfilby

1
John, tôi 100% đồng ý với bạn .. Imbum Câu hỏi gần như là "bạn chấp nhận bao nhiêu". Sloppy là cẩu thả .. Làm thế nào về tôi để lại một con tôm phía sau màn hình của bạn. hôi thối là hôi thối. Mỗi khi chúng tôi hang động, ngành công nghiệp của chúng tôi hang động một chút. Nếu bạn biết có rò rỉ và bạn biết bạn đã gây ra nó, thì bạn nên sửa nó.
baash05

37

Nhiều người dường như cảm thấy rằng một khi bạn giải phóng bộ nhớ, nó sẽ ngay lập tức trở lại hệ điều hành và có thể được các chương trình khác sử dụng.

Điều này không đúng. Hệ điều hành thường quản lý bộ nhớ trong các trang 4KiB. mallocvà các loại quản lý bộ nhớ khác lấy các trang từ HĐH và quản lý chúng khi chúng thấy phù hợp. Rất có khả năng free()sẽ không trả lại các trang cho hệ điều hành, với giả định rằng chương trình của bạn sẽ có nhiều bộ nhớ hơn sau này.

Tôi không nói rằng free()không bao giờ trả lại bộ nhớ cho hệ điều hành. Nó có thể xảy ra, đặc biệt nếu bạn đang giải phóng bộ nhớ lớn. Nhưng không có gì đảm bảo.

Một thực tế quan trọng: Nếu bạn không còn bộ nhớ trống mà bạn không còn cần nữa, mallocs hơn nữa được đảm bảo sẽ tiêu thụ nhiều bộ nhớ hơn . Nhưng nếu bạn rảnh trước, malloc có thể sử dụng lại bộ nhớ đã giải phóng.

Điều này có ý nghĩa gì trong thực tế? Điều đó có nghĩa là nếu bạn biết rằng chương trình của bạn sẽ không cần thêm bộ nhớ kể từ bây giờ (ví dụ: trong giai đoạn dọn dẹp), việc giải phóng bộ nhớ không quá quan trọng. Tuy nhiên, nếu chương trình có thể phân bổ thêm bộ nhớ sau này, bạn nên tránh rò rỉ bộ nhớ - đặc biệt là những trường hợp có thể xảy ra lặp đi lặp lại.

Cũng xem bình luận này để biết thêm chi tiết về lý do tại sao giải phóng bộ nhớ ngay trước khi chấm dứt là xấu.

Một nhà bình luận dường như không hiểu rằng việc gọi điện free()không tự động cho phép các chương trình khác sử dụng bộ nhớ đã giải phóng. Nhưng đó là toàn bộ quan điểm của câu trả lời này!

Vì vậy, để thuyết phục mọi người, tôi sẽ chứng minh một ví dụ trong đó free () làm rất ít điều tốt. Để làm cho toán dễ theo dõi, tôi sẽ giả vờ rằng HĐH quản lý bộ nhớ trong 4000 trang byte.

Giả sử bạn phân bổ mười nghìn khối 100 byte (để đơn giản, tôi sẽ bỏ qua bộ nhớ bổ sung sẽ được yêu cầu để quản lý các phân bổ này). Điều này tiêu tốn 1MB, hoặc 250 trang. Nếu sau đó bạn giải phóng 9000 khối này một cách ngẫu nhiên, bạn chỉ còn lại 1000 khối - nhưng chúng nằm rải rác khắp nơi. Theo thống kê, khoảng 5 trong số các trang sẽ trống. Mỗi nhóm khác sẽ có ít nhất một khối được phân bổ trong đó. Con số đó lên tới 980KB bộ nhớ, mà hệ điều hành không thể lấy lại được - mặc dù hiện tại bạn chỉ có 100KB được phân bổ!

Mặt khác, giờ đây bạn có thể thêm malloc () 9000 khối mà không tăng dung lượng bộ nhớ mà chương trình của bạn đang sử dụng.

Ngay cả khi về mặt kỹ thuậtfree() có thể trả lại bộ nhớ cho HĐH, nó có thể không làm như vậy. cần đạt được sự cân bằng giữa vận hành nhanh và tiết kiệm bộ nhớ. Và bên cạnh đó, một chương trình đã được phân bổ rất nhiều bộ nhớ và sau đó giải phóng nó có khả năng sẽ thực hiện lại. Một máy chủ web cần xử lý yêu cầu sau khi yêu cầu sau khi yêu cầu - sẽ hợp lý khi giữ một số bộ nhớ "chùng" để bạn không cần phải yêu cầu HĐH cho bộ nhớ mọi lúc.free()


1
Điều gì sẽ xảy ra nếu, các chương trình khác yêu cầu bộ nhớ mà chương trình của bạn đang giữ một cách không cần thiết, do đó, mặc dù bạn có thể không cần thêm mallocs, miễn phí () không gian bộ nhớ không sử dụng :)
MN

2
Bạn đã hoàn toàn bỏ lỡ quan điểm của tôi. Khi bạn giải phóng bộ nhớ (), các chương trình khác không thể sử dụng nó !! (Đôi khi, họ có thể, đặc biệt nếu bạn giải phóng khối bộ nhớ lớn. Nhưng thường thì họ không thể!) Tôi sẽ chỉnh sửa bài đăng của mình để làm cho điều này rõ ràng hơn.
Artelius

27

Không có gì sai về mặt khái niệm với việc làm sạch os sau khi ứng dụng được chạy.

Nó thực sự phụ thuộc vào ứng dụng và cách nó sẽ được chạy. Việc rò rỉ liên tục xảy ra trong một ứng dụng cần chạy trong nhiều tuần phải được xử lý, nhưng một công cụ nhỏ tính toán kết quả mà không cần bộ nhớ quá cao không phải là vấn đề.

Có một lý do tại sao nhiều ngôn ngữ kịch bản không rác thu thập các tài liệu tham khảo theo chu kỳ cho các kiểu sử dụng của chúng, đó không phải là vấn đề thực sự và do đó sẽ gây lãng phí tài nguyên như bộ nhớ bị lãng phí.


Về ngôn ngữ kịch bản: Python sử dụng tính năng đếm lại nhưng chỉ có một GC để tham khảo theo chu kỳ miễn phí. Trong các ngôn ngữ khác, lập trình viên thường tránh hoàn toàn các tham chiếu theo chu kỳ, điều này tạo ra các vấn đề khác.
Blaisorblade

Các phiên bản trước của PHP không giải phóng bộ nhớ, chúng chỉ chạy từ đầu đến cuối tăng trưởng trong bộ nhớ - sau 0,1 giây thời gian thực hiện thông thường, tập lệnh sẽ thoát và tất cả bộ nhớ sẽ được lấy lại.
Arafangion

19

Tôi tin rằng câu trả lời là không, không bao giờ cho phép rò rỉ bộ nhớ và tôi có một vài lý do mà tôi chưa thấy rõ ràng. Có những câu trả lời kỹ thuật tuyệt vời ở đây nhưng tôi nghĩ rằng câu trả lời thực sự xoay quanh nhiều lý do xã hội / con người hơn.

(Đầu tiên, lưu ý rằng như những người khác đã đề cập, một sự rò rỉ đúng là khi chương trình của bạn, bất cứ lúc nào, mất theo dõi tài nguyên bộ nhớ mà nó đã được phân bổ. Trong C, điều này xảy ra khi bạn malloc()đến một con trỏ và để cho rằng phạm vi con trỏ nghỉ mà không làm một free()Đầu tiên.)

Mấu chốt quan trọng của quyết định của bạn ở đây là thói quen. Khi bạn viết mã bằng ngôn ngữ sử dụng con trỏ, bạn sẽ sử dụng con trỏ rất nhiều . Và con trỏ là nguy hiểm; chúng là cách dễ nhất để thêm tất cả các cách xử lý sự cố nghiêm trọng vào mã của bạn.

Khi bạn đang viết mã, đôi khi bạn sẽ ở trên bóng và đôi khi bạn sẽ mệt mỏi hoặc tức giận hoặc lo lắng. Trong những khoảng thời gian hơi mất tập trung đó, bạn đang mã hóa nhiều hơn cho chế độ lái tự động. Hiệu ứng tự động không phân biệt giữa mã một lần và mô-đun trong dự án lớn hơn. Trong những khoảng thời gian đó, những thói quen bạn thiết lập là những gì sẽ kết thúc trong cơ sở mã của bạn.

Vì vậy, không bao giờ cho phép rò rỉ bộ nhớ vì lý do tương tự mà bạn vẫn nên kiểm tra điểm mù của mình khi chuyển làn ngay cả khi bạn là chiếc xe duy nhất trên đường vào lúc này. Trong thời gian khi bộ não hoạt động của bạn bị phân tâm, những thói quen tốt là tất cả những gì có thể cứu bạn khỏi những sai lầm tai hại.

Ngoài vấn đề "thói quen", con trỏ rất phức tạp và thường đòi hỏi nhiều năng lực não bộ để theo dõi tinh thần. Tốt nhất là không "làm vẩn đục nước" khi nói đến việc sử dụng con trỏ của bạn, đặc biệt là khi bạn mới lập trình.

Có một khía cạnh xã hội hơn nữa. Bằng cách sử dụng đúng malloc()free(), bất cứ ai nhìn vào mã của bạn sẽ thấy thoải mái; bạn đang quản lý tài nguyên của bạn. Tuy nhiên, nếu bạn không, họ sẽ ngay lập tức nghi ngờ vấn đề.

Có thể bạn đã tìm ra rằng rò rỉ bộ nhớ không ảnh hưởng gì đến bối cảnh này, nhưng mọi người duy trì mã của bạn cũng sẽ phải xử lý nó trong đầu khi anh ta đọc đoạn mã đó. Bằng cách sử dụng, free()bạn loại bỏ sự cần thiết phải xem xét vấn đề.

Cuối cùng, lập trình đang viết một mô hình tinh thần của một quá trình sang một ngôn ngữ rõ ràng để một người và một máy tính có thể hiểu hoàn toàn quy trình nói trên. Một phần quan trọng của thực hành lập trình tốt là không bao giờ đưa ra sự mơ hồ không cần thiết.

Lập trình thông minh là linh hoạt và chung chung. Lập trình xấu là mơ hồ.


Tôi thích ý tưởng thói quen. Tôi cũng đồng ý. Nếu tôi thấy rò rỉ bộ nhớ, tôi luôn tự hỏi những gì mà bộ mã hóa đã cắt. Đặc biệt là nếu nó rõ ràng
baash05

Đây là câu trả lời tốt nhất cho đến nay. Tôi đã lập trình trong C ++ được 5 năm và tôi chưa bao giờ viết một lần rò rỉ bộ nhớ. Lý do là tôi không viết mã có xu hướng rò rỉ bộ nhớ. Thiết kế C ++ tốt hiếm khi bạn sử dụng new, do đó loại bỏ hầu hết các rò rỉ bộ nhớ ngay lập tức. Chỉ khi bạn hoàn toàn phải làm bạn sử dụng new. Kết quả của điều đó newphải được đặt ngay lập tức vào một con trỏ thông minh. Nếu bạn tuân theo hai quy tắc đó, đơn giản là bạn sẽ không bao giờ rò rỉ bộ nhớ (chặn một lỗi trong thư viện). Trường hợp duy nhất còn lại là shared_ptrchu kỳ, trong trường hợp đó bạn phải biết sử dụng weak_ptr.
David Stone

15

Tôi nghĩ trong tình huống của bạn, câu trả lời có thể là nó ổn. Nhưng bạn chắc chắn cần phải ghi nhận rằng rò rỉ bộ nhớ là một quyết định có ý thức. Bạn không muốn một lập trình viên bảo trì đi cùng, đưa mã của bạn vào trong một hàm và gọi nó là một triệu lần. Vì vậy, nếu bạn đưa ra quyết định rằng rò rỉ là ổn, bạn cần ghi lại nó (TRONG LỚP LỚN) cho bất cứ ai có thể phải làm việc trên chương trình trong tương lai.

Nếu đây là thư viện của bên thứ ba, bạn có thể bị mắc kẹt. Nhưng chắc chắn tài liệu rằng rò rỉ này xảy ra.

Nhưng về cơ bản, nếu rò rỉ bộ nhớ là một đại lượng đã biết như bộ đệm 512 KB hoặc một cái gì đó thì đó không phải là vấn đề. Nếu rò rỉ bộ nhớ tiếp tục phát triển như mỗi lần bạn gọi thư viện, bộ nhớ của bạn tăng thêm 512KB và không được giải phóng, thì bạn có thể gặp vấn đề. Nếu bạn ghi lại nó và kiểm soát số lần cuộc gọi được thực hiện, nó có thể được quản lý. Nhưng sau đó, bạn thực sự cần tài liệu vì trong khi 512 không nhiều, thì 512 trên một triệu cuộc gọi là rất nhiều.

Ngoài ra, bạn cần kiểm tra tài liệu hệ điều hành của bạn. Nếu đây là một thiết bị nhúng, có thể có các hệ điều hành không giải phóng tất cả bộ nhớ khỏi chương trình thoát. Tôi không chắc, có lẽ điều này không đúng. Nhưng nó đáng để xem xét.


3
"Nhưng bạn chắc chắn cần phải ghi lại rằng rò rỉ bộ nhớ là một quyết định có ý thức." Cảm ơn Thượng Đế. Điểm tốt nhất được thực hiện cho đến nay.
hại

15

Tôi sẽ đưa ra câu trả lời không phổ biến nhưng thực tế rằng nó luôn sai khi giải phóng bộ nhớ trừ khi làm như vậy sẽ làm giảm việc sử dụng bộ nhớ của chương trình của bạn . Ví dụ, một chương trình thực hiện một phân bổ duy nhất hoặc một loạt các phân bổ để tải tập dữ liệu mà nó sẽ sử dụng cho toàn bộ thời gian của nó không cần phải giải phóng bất cứ điều gì. Trong trường hợp phổ biến hơn của một chương trình lớn có yêu cầu bộ nhớ rất động (nghĩ về trình duyệt web), rõ ràng bạn nên giải phóng bộ nhớ mà bạn không còn sử dụng ngay khi có thể (ví dụ: đóng tab / tài liệu / v.v.) , nhưng không có lý do để giải phóng bất cứ điều gì khi người dùng chọn nhấp vào "thoát" và làm như vậy thực sự có hại cho trải nghiệm người dùng.

Tại sao? Giải phóng bộ nhớ đòi hỏi phải chạm vào bộ nhớ. Ngay cả khi việc triển khai malloc của hệ thống của bạn xảy ra không lưu trữ siêu dữ liệu liền kề với các khối bộ nhớ được phân bổ, rất có thể bạn sẽ đi bộ các cấu trúc đệ quy chỉ để tìm tất cả các con trỏ bạn cần để giải phóng.

Bây giờ, giả sử chương trình của bạn đã hoạt động với một khối lượng dữ liệu lớn, nhưng đã không chạm vào hầu hết trong một thời gian (một lần nữa, trình duyệt web là một ví dụ tuyệt vời). Nếu người dùng đang chạy nhiều ứng dụng, một phần tốt của dữ liệu đó có thể đã được hoán đổi vào đĩa. Nếu bạn chỉ thoát (0) hoặc trở về từ chính, nó sẽ thoát ngay lập tức. Trải nghiệm người dùng tuyệt vời. Nếu bạn gặp rắc rối khi cố gắng giải phóng mọi thứ, bạn có thể mất 5 giây hoặc nhiều hơn để hoán đổi tất cả dữ liệu trở lại, chỉ để vứt nó đi ngay sau đó. Lãng phí thời gian của người dùng. Lãng phí tuổi thọ pin của máy tính xách tay. Lãng phí hao mòn trên đĩa cứng.

Đây không chỉ là lý thuyết. Bất cứ khi nào tôi thấy mình có quá nhiều ứng dụng được tải và đĩa bắt đầu đập, tôi thậm chí không xem xét nhấp vào "thoát". Tôi đến một thiết bị đầu cuối nhanh nhất có thể và gõ killall -9 ... bởi vì tôi biết "thoát" sẽ chỉ làm cho nó tồi tệ hơn.


5
Yêu câu trích dẫn này của Raymond Chen: "Tòa nhà đang bị phá hủy. Đừng bận tâm quét sàn và đổ thùng rác và xóa bảng trắng. Và đừng xếp hàng ở lối ra tòa nhà để mọi người có thể di chuyển vào / Tất cả những gì bạn đang làm là khiến nhóm phá hủy chờ bạn hoàn thành những nhiệm vụ dọn dẹp vô nghĩa này. " ( blog.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683 )
Andreas Magnusson

11

Tôi chắc chắn rằng ai đó có thể đưa ra lý do để nói Có, nhưng đó sẽ không phải là tôi. Thay vì nói không, tôi sẽ nói rằng đây không phải là câu hỏi có / không. Có nhiều cách để quản lý hoặc chứa rò rỉ bộ nhớ và nhiều hệ thống có chúng.

Có các hệ thống của NASA trên các thiết bị rời khỏi trái đất có kế hoạch cho việc này. Các hệ thống sẽ tự động khởi động lại thường xuyên để rò rỉ bộ nhớ sẽ không gây tử vong cho hoạt động chung. Chỉ là một ví dụ về ngăn chặn.


Đó thực sự là một ví dụ về lão hóa phần mềm. Môn học hấp dẫn
Konrad Rudolph

Khởi động lại tự động thường xuyên như vậy, phải không? NASA hả? (* nhìn vào đĩa CD cài đặt Microsoft Windows cũ *) Điều này giải thích rất nhiều ...
Christian Severin

8

Nếu bạn phân bổ bộ nhớ và sử dụng nó cho đến dòng cuối cùng của chương trình, đó không phải là một rò rỉ. Nếu bạn phân bổ bộ nhớ và quên nó đi, ngay cả khi dung lượng bộ nhớ không tăng, đó là một vấn đề. Bộ nhớ được phân bổ nhưng không sử dụng này có thể khiến các chương trình khác chạy chậm hơn hoặc không hoạt động.


Không thực sự, vì nếu nó không được sử dụng, nó sẽ chỉ được phân trang. Khi ứng dụng thoát, tất cả bộ nhớ được giải phóng.
Nhật thực

Miễn là nó được phân bổ các chương trình khác sẽ không thể sử dụng nó. Nó sẽ không được phân trang nếu bạn không giải quyết nó.
Bill Lizard

Tất nhiên nó sẽ - đó là những gì bộ nhớ ảo là tất cả về. Bạn có thể có 1 GB RAM thực tế và vẫn có 4 quy trình, mỗi bộ phân bổ đầy đủ 2 GB bộ nhớ ảo (miễn là tệp trang của bạn đủ lớn).
Nhật thực

Tất nhiên, bạn sẽ gặp các vấn đề phân trang khó chịu nếu mỗi quá trình đó đang tích cực sử dụng tất cả bộ nhớ đó.
Nhật thực

Được rồi, tôi hiểu những gì bạn đang nói về bây giờ. Nếu bạn phân bổ bộ nhớ bạn không sử dụng, bạn sẽ giảm nhu cầu phân trang. Nếu bạn giữ nó được phân bổ, ứng dụng của bạn sẽ vẫn giữ nó khi được phân trang lại.
Bill the Lizard

8

Tôi có thể đếm bằng một tay số lần rò rỉ "lành tính" mà tôi đã thấy qua thời gian.

Vì vậy, câu trả lời là rất có trình độ.

Một ví dụ. Nếu bạn có một tài nguyên đơn lẻ cần một bộ đệm để lưu trữ một hàng đợi tròn hoặc deque nhưng không biết bộ đệm sẽ cần lớn đến mức nào và không đủ khả năng chi trả cho việc khóa hoặc mọi người đọc, sau đó phân bổ bộ đệm nhân đôi theo cấp số nhân nhưng không giải phóng những cái cũ sẽ rò rỉ một lượng bộ nhớ giới hạn cho mỗi hàng đợi / deque. Lợi ích cho những điều này là chúng tăng tốc đáng kể mọi truy cập và có thể thay đổi tính không triệu chứng của các giải pháp đa bộ xử lý bằng cách không bao giờ mạo hiểm tranh chấp cho một khóa.

Tôi đã thấy cách tiếp cận này được sử dụng để mang lại lợi ích lớn cho những thứ có số lượng cố định rất rõ ràng như các công cụ đánh cắp công việc trên CPU và ở mức độ thấp hơn nhiều trong bộ đệm được sử dụng để giữ đơn lẻ /proc/self/maps trạng thái trong trình thu gom rác bảo thủ của Hans Boehm cho C / C ++, được sử dụng để phát hiện các bộ gốc, v.v.

Mặc dù về mặt kỹ thuật là một sự rò rỉ, cả hai trường hợp này đều bị giới hạn về kích thước và trong trường hợp ăn cắp công việc có thể phát triển được, có một chiến thắng lớn về hiệu suất để đổi lấy hệ số giới hạn tăng 2 lần sử dụng bộ nhớ cho hàng đợi.


1
Bạn có thể sử dụng con trỏ nguy hiểm để ngăn chặn rò rỉ.
Demi

8

Nếu bạn phân bổ một đống heap khi bắt đầu chương trình và bạn không giải phóng nó khi bạn thoát, đó không phải là rò rỉ bộ nhớ mỗi se. Rò rỉ bộ nhớ là khi chương trình của bạn lặp lại một phần của mã và mã đó phân bổ heap và sau đó "mất dấu vết" của nó mà không giải phóng nó.

Trong thực tế, không cần thực hiện cuộc gọi đến free () hoặc xóa ngay trước khi bạn thoát. Khi quá trình thoát, tất cả bộ nhớ của nó được HĐH thu hồi (đây chắc chắn là trường hợp của POSIX. Trên các HĐH khác - đặc biệt là các nhúng được nhúng - YMMV).

Lưu ý duy nhất tôi có khi không giải phóng bộ nhớ khi thoát ra là nếu bạn từng cấu trúc lại chương trình của mình để nó trở thành một dịch vụ chờ đầu vào, làm bất cứ điều gì chương trình của bạn làm, sau đó lặp đi lặp lại để chờ một cuộc gọi dịch vụ khác, sau đó những gì bạn đã mã hóa có thể biến thành rò rỉ bộ nhớ.


Tôi có ý kiến ​​khác. Đó một rò rỉ bộ nhớ cho mỗi se.
Konrad Rudolph

Đây không phải là một rò rỉ cho đến khi bạn "mất" tham chiếu đến đối tượng. Có lẽ, nếu bộ nhớ được sử dụng trong suốt thời gian của chương trình, thì nó không bị rò rỉ. Nếu tham chiếu không bị mất cho đến khi exit () được gọi, thì đó hoàn toàn không phải là một rò rỉ.
nsayer

Amiga DOS là O / SI cuối cùng nhìn vào mà không làm sạch đằng sau các quy trình. Tuy nhiên, hãy lưu ý rằng bộ nhớ chia sẻ System V IPC có thể bị bỏ lại ngay cả khi không có quá trình nào sử dụng nó.
Jonathan Leffler

Palm không giải phóng bộ nhớ "rò rỉ" cho đến khi bạn hotsync. Nó đến tốt sau amiga. Tôi đã chạy các ứng dụng trên trình giả lập lòng bàn tay bị rò rỉ .. Chưa bao giờ chúng tìm đường đến lòng bàn tay thực sự của tôi.
baash05

6

đây là tên miền cụ thể đến nỗi nó khó có thể trả lời. sử dụng cái đầu kỳ dị của bạn

  • hệ điều hành tàu con thoi: không, không cho phép rò rỉ bộ nhớ
  • mã bằng chứng phát triển nhanh chóng: sửa chữa tất cả những rò rỉ bộ nhớ là một sự lãng phí thời gian.

và có một phổ các tình huống trung gian.

chi phí cơ hội ($$$) của việc trì hoãn phát hành sản phẩm để khắc phục tất cả nhưng rò rỉ bộ nhớ tồi tệ nhất thường làm cho mọi người cảm thấy "cẩu thả hoặc không chuyên nghiệp". Sếp của bạn trả tiền cho bạn để kiếm tiền cho anh ta, không để có được cảm giác ấm áp, mờ nhạt.


2
Thái độ rất thiển cận. Về cơ bản, bạn đang nói rằng không cần phải sử dụng các thực tiễn lập trình cơ bản cho đến khi một lỗi được phát hiện là do các thực tiễn đó gây ra. Vấn đề là phần mềm được viết bằng các phương pháp cẩu thả có xu hướng có nhiều khiếm khuyết hơn phần mềm không có.
John Dibling

1
Tôi không tin tất cả. Và quản lý bộ nhớ phức tạp hơn so với viết phương pháp sạch.
Dustin Getz

1
Dustin rõ ràng hoạt động trong thế giới thực như hầu hết chúng ta, nơi chúng ta liên tục làm việc chống lại thời hạn điên rồ để theo kịp đối thủ. Vì vậy, đối phó với các lỗi nên được thực hiện một cách thực tế. Bằng cách lãng phí quá nhiều thời gian cho các lỗi không quan trọng trong các chương trình không quan trọng, bạn sẽ không hoàn thành công việc của mình.
Wouter van Nifterick

Vấn đề với thái độ này là: khi nào bạn bắt đầu sửa chữa rò rỉ? "OK, đó là một cỗ máy, nhưng nó chỉ là than chứ không phải Uranium. Tại sao phải sửa rò rỉ ở đây?" - Tôi đã học được trong thế giới thực rằng nếu bạn không làm điều đúng đắn ngay từ đầu, mọi lúc, điều đó sẽ không bao giờ xảy ra. Thái độ đó tạo ra các dự án "hoàn thành 99%" sau hai tuần và duy trì như vậy trong hai tháng.
peterchen

5

Trước tiên bạn phải nhận ra rằng có một sự khác biệt lớn giữa rò rỉ bộ nhớ nhận thức và rò rỉ bộ nhớ thực tế. Các công cụ phân tích rất thường xuyên sẽ báo cáo nhiều cá trích đỏ và gắn nhãn một cái gì đó đã bị rò rỉ (bộ nhớ hoặc tài nguyên như tay cầm, v.v.) trong đó thực sự không có. Thường thì điều này là do kiến ​​trúc của công cụ phân tích. Ví dụ, một số công cụ phân tích nhất định sẽ báo cáo các đối tượng thời gian chạy khi rò rỉ bộ nhớ vì nó không bao giờ thấy các đối tượng đó được giải phóng. Nhưng sự phân bổ xảy ra trong mã tắt máy của bộ thực thi, công cụ phân tích có thể không nhìn thấy được.

Như đã nói, vẫn sẽ có lúc bạn bị rò rỉ bộ nhớ thực tế hoặc rất khó tìm hoặc rất khó khắc phục. Vì vậy, bây giờ câu hỏi trở thành là bao giờ OK để lại chúng trong mã?

Câu trả lời lý tưởng là "không, không bao giờ." Một câu trả lời thực dụng hơn có thể là "không, gần như không bao giờ." Rất thường xuyên trong cuộc sống thực, bạn có số lượng tài nguyên và thời gian hạn chế để giải quyết và danh sách các nhiệm vụ vô tận. Khi một trong những nhiệm vụ loại bỏ rò rỉ bộ nhớ, luật giảm dần trở lại rất thường xuất hiện để chơi. Bạn có thể loại bỏ 98% tất cả các rò rỉ bộ nhớ trong một ứng dụng trong một tuần, nhưng 2% còn lại có thể mất vài tháng. Trong một số trường hợp, thậm chí có thể không thể loại bỏ một số rò rỉ nhất định do kiến ​​trúc của ứng dụng mà không có cấu trúc lại mã chính. Bạn phải cân nhắc chi phí và lợi ích của việc loại bỏ 2% còn lại.


5

Trong loại bối cảnh câu hỏi này là tất cả mọi thứ. Cá nhân tôi không thể chịu được rò rỉ, và trong mã của tôi, tôi đã cố gắng khắc phục chúng nếu chúng mọc lên, nhưng nó không phải lúc nào cũng đáng để sửa rò rỉ, và khi mọi người trả tiền cho tôi theo giờ tôi có nói với họ rằng tôi không đáng để tôi sửa lỗi rò rỉ mã của họ. Tôi sẽ cho bạn một ví dụ:

Tôi đã xử lý một dự án, thực hiện một số công việc hoàn hảo và sửa rất nhiều lỗi. Có một rò rỉ trong quá trình khởi tạo ứng dụng mà tôi đã theo dõi và hiểu đầy đủ. Sửa nó đúng cách sẽ cần một ngày hoặc tái cấu trúc một đoạn mã chức năng khác. Tôi có thể đã thực hiện một vài thứ hacky (như nhét giá trị vào toàn cầu và chộp lấy một số điểm tôi biết rằng nó không còn được sử dụng để giải phóng), nhưng điều đó sẽ gây ra nhiều nhầm lẫn hơn cho người tiếp theo phải chạm vào mã.

Cá nhân tôi sẽ không viết mã theo cách đó ngay từ đầu, nhưng hầu hết chúng ta không phải luôn luôn làm việc trên các cơ sở mã được thiết kế tốt nguyên sơ, và đôi khi bạn phải nhìn vào những điều này một cách thực tế. Lượng thời gian cần thiết để tôi khắc phục sự cố rò rỉ 150 byte thay vào đó có thể được dành để thực hiện các cải tiến thuật toán giúp loại bỏ megabyte ram.

Cuối cùng, tôi đã quyết định rằng rò rỉ 150 byte cho một ứng dụng sử dụng xung quanh một ram và chạy trên một máy chuyên dụng không đáng để sửa nó, vì vậy tôi đã viết một bình luận nói rằng nó bị rò rỉ, những gì cần phải thay đổi để sửa nó, và tại sao nó không có giá trị tại thời điểm đó.


Thông minh. Đặc biệt là do rò rỉ là trong quá trình khởi tạo, điều đó có nghĩa là nó sẽ không tích lũy trong thời gian chạy của ứng dụng.
Demi

5

Trong khi hầu hết các câu trả lời tập trung vào rò rỉ bộ nhớ thực (điều này không ổn bao giờ, bởi vì chúng là dấu hiệu của mã hóa cẩu thả), phần này của câu hỏi có vẻ thú vị hơn đối với tôi:

Điều gì sẽ xảy ra nếu bạn phân bổ một số bộ nhớ và sử dụng nó cho đến dòng mã cuối cùng trong ứng dụng của bạn (ví dụ: bộ giải mã đối tượng toàn cầu)? Miễn là mức tiêu thụ bộ nhớ không tăng theo thời gian, bạn có thể tin tưởng HĐH sẽ giải phóng bộ nhớ cho bạn khi ứng dụng của bạn chấm dứt (trên Windows, Mac và Linux) không? Bạn thậm chí có thể coi đây là một rò rỉ bộ nhớ thực nếu bộ nhớ được sử dụng liên tục cho đến khi nó được hệ điều hành giải phóng.

Nếu bộ nhớ liên quan được sử dụng, bạn không thể giải phóng nó trước khi chương trình kết thúc. Việc miễn phí được thực hiện bằng cách thoát chương trình hay bởi HĐH không thành vấn đề. Miễn là điều này được ghi lại, do đó, sự thay đổi đó không gây ra rò rỉ bộ nhớ thực và miễn là không có chức năng dọn dẹp C ++ hoặc chức năng dọn dẹp C liên quan đến hình ảnh. Một tệp không đóng có thể được tiết lộ thông qua một FILEđối tượng bị rò rỉ , nhưng một fclose () bị thiếu cũng có thể khiến bộ đệm không bị xóa.

Vì vậy, trở lại trường hợp ban đầu, bản thân IMHO hoàn toàn ổn, đến mức Valgrind, một trong những máy phát hiện rò rỉ mạnh nhất, sẽ chỉ xử lý rò rỉ như vậy nếu được yêu cầu. Trên Valgrind, khi bạn ghi đè lên một con trỏ mà không giải phóng nó trước, nó sẽ bị coi là rò rỉ bộ nhớ, vì nó có nhiều khả năng xảy ra lần nữa và khiến cho đống dữ liệu tăng lên vô tận.

Sau đó, không có khối bộ nhớ nfreed nào vẫn có thể truy cập. Người ta có thể đảm bảo giải phóng tất cả chúng ở lối ra, nhưng bản thân nó chỉ là một sự lãng phí thời gian. Vấn đề là nếu họ có thể được giải thoát trước đây . Giảm tiêu thụ bộ nhớ là hữu ích trong mọi trường hợp.


Wow ... một người biết rò rỉ bộ nhớ là gì.
Simon Buchan

4

Tôi đồng ý với vfilby - nó phụ thuộc. Trong Windows, chúng tôi coi rò rỉ bộ nhớ là lỗi tương đối nghiêm trọng. Nhưng, nó phụ thuộc rất nhiều vào thành phần.

Ví dụ, rò rỉ bộ nhớ không quá nghiêm trọng đối với các thành phần hiếm khi chạy và trong khoảng thời gian giới hạn. Các thành phần này chạy, làm công việc theire, sau đó thoát. Khi họ thoát tất cả bộ nhớ của họ được giải phóng ngầm.

Tuy nhiên, rò rỉ bộ nhớ trong các dịch vụ hoặc các thành phần chạy dài khác (như vỏ) là rất nghiêm trọng. Lý do là những con bọ này 'đánh cắp' bộ nhớ theo thời gian. Cách duy nhất để phục hồi điều này là khởi động lại các thành phần. Hầu hết mọi người không biết cách khởi động lại một dịch vụ hoặc trình bao - vì vậy nếu hiệu suất hệ thống của họ bị ảnh hưởng, họ chỉ cần khởi động lại.

Vì vậy, nếu bạn bị rò rỉ - hãy đánh giá tác động của nó theo hai cách

  1. Để phần mềm của bạn và trải nghiệm người dùng của bạn.
  2. Đối với hệ thống (và người dùng) về mặt tiết kiệm với tài nguyên hệ thống.
  3. Tác động của việc sửa chữa đối với bảo trì và độ tin cậy.
  4. Khả năng gây ra một hồi quy ở một nơi khác.

Foredecker


3. Tác động đến việc bảo trì phần mềm.
peterchen

3

Ngay cả khi bạn chắc chắn rằng rò rỉ bộ nhớ 'đã biết' của bạn sẽ không gây ra sự tàn phá, đừng làm điều đó. Tốt nhất, nó sẽ mở đường cho bạn mắc một lỗi tương tự và có thể nghiêm trọng hơn ở một thời điểm và địa điểm khác.

Đối với tôi, hỏi điều này giống như đặt câu hỏi "Tôi có thể vượt đèn đỏ lúc 3 giờ sáng khi không có ai xung quanh không?". Chắc chắn, nó có thể không gây ra bất kỳ rắc rối nào tại thời điểm đó nhưng nó sẽ cung cấp một đòn bẩy để bạn làm điều tương tự trong giờ cao điểm!


3

Không, bạn không nên có rò rỉ rằng hệ điều hành sẽ làm sạch cho bạn. Lý do (không được đề cập trong các câu trả lời ở trên như tôi có thể kiểm tra) là bạn không bao giờ biết khi nào main () của bạn sẽ được sử dụng lại làm hàm / mô-đun trong chương trình khác . Nếu hàm chính () của bạn trở thành một hàm được gọi thường xuyên trong phần mềm của người khác - phần mềm này sẽ bị rò rỉ bộ nhớ ăn theo bộ nhớ theo thời gian.

KIV


3

Tôi đoán sẽ ổn nếu bạn viết chương trình có nghĩa là rò rỉ bộ nhớ (tức là để kiểm tra tác động của rò rỉ bộ nhớ đến hiệu năng hệ thống).


3

Tôi ngạc nhiên khi thấy rất nhiều định nghĩa không chính xác về rò rỉ bộ nhớ thực sự là gì. Nếu không có một định nghĩa cụ thể, một cuộc thảo luận về việc đó có phải là điều xấu hay không sẽ đi đến đâu.

Như một số nhà bình luận đã chỉ ra một cách đúng đắn, rò rỉ bộ nhớ chỉ xảy ra khi bộ nhớ được cấp phát bởi một quá trình vượt quá phạm vi đến mức mà quá trình không còn có thể tham chiếu hoặc xóa nó.

Một quá trình chiếm nhiều bộ nhớ hơn không nhất thiết phải bị rò rỉ. Miễn là nó có thể tham chiếu và giải phóng bộ nhớ đó, thì nó vẫn nằm dưới sự kiểm soát rõ ràng của quy trình và không bị rò rỉ. Quá trình này có thể được thiết kế tồi, đặc biệt là trong bối cảnh của một hệ thống mà bộ nhớ bị hạn chế, nhưng điều này không giống như rò rỉ. Ngược lại, việc mất phạm vi, giả sử, bộ đệm 32 byte vẫn bị rò rỉ, mặc dù lượng bộ nhớ bị rò rỉ là nhỏ. Nếu bạn nghĩ rằng điều này là không đáng kể, hãy đợi cho đến khi ai đó kết thúc một thuật toán xung quanh cuộc gọi thư viện của bạn và gọi nó 10.000 lần.

Tôi thấy không có lý do gì để cho phép rò rỉ trong mã của riêng bạn, tuy nhỏ. Các ngôn ngữ lập trình hiện đại như C và C ++ rất có ích để giúp các lập trình viên ngăn chặn các rò rỉ đó và hiếm khi có một lý lẽ tốt để không áp dụng các kỹ thuật lập trình tốt - đặc biệt là khi kết hợp với các phương tiện ngôn ngữ cụ thể - để tránh rò rỉ.

Liên quan đến mã của bên thứ ba hoặc bên thứ ba, nơi mà sự kiểm soát của bạn đối với chất lượng hoặc khả năng thực hiện thay đổi có thể bị hạn chế rất nhiều, tùy thuộc vào mức độ nghiêm trọng của rò rỉ, bạn có thể buộc phải chấp nhận hoặc thực hiện hành động giảm thiểu như khởi động lại quy trình của mình thường xuyên để giảm bớt ảnh hưởng của rò rỉ.

Có thể không thể thay đổi hoặc thay thế mã (rò rỉ) hiện có, và do đó bạn có thể bị ràng buộc chấp nhận nó. Tuy nhiên, điều này không giống như tuyên bố rằng nó ổn.


2

Nó thực sự không phải là một rò rỉ nếu nó cố ý và nó không phải là vấn đề trừ khi nó là một bộ nhớ đáng kể, hoặc có thể trở thành một lượng đáng kể của bộ nhớ. Nó khá phổ biến để không dọn dẹp phân bổ toàn cầu trong suốt vòng đời của một chương trình. Nếu rò rỉ trong một máy chủ hoặc ứng dụng chạy dài, phát triển theo thời gian, thì đó là một vấn đề.


2

Tôi nghĩ bạn đã trả lời câu hỏi của riêng bạn. Hạn chế lớn nhất là cách chúng can thiệp vào các công cụ phát hiện rò rỉ bộ nhớ, nhưng tôi nghĩ rằng nhược điểm đó là một nhược điểm lớn đối với một số loại ứng dụng.

Tôi làm việc với các ứng dụng máy chủ cũ được cho là cứng như đá nhưng chúng bị rò rỉ và toàn cầu DO cản trở các công cụ phát hiện bộ nhớ. Đây là một vấn đề lớn.

Trong cuốn sách "Sụp đổ" của Jared Diamond, tác giả tự hỏi về việc anh chàng nghĩ gì về việc chặt cây cuối cùng trên đảo Phục Sinh, cái cây anh ta cần có để chế tạo một chiếc xuồng để ra khỏi đảo. Tôi tự hỏi về ngày nhiều năm trước khi toàn cầu đầu tiên đó được thêm vào cơ sở mã của chúng tôi. Đó là ngày đáng lẽ phải bị bắt.


2

Tôi thấy vấn đề tương tự như tất cả các câu hỏi kịch bản như thế này: Điều gì xảy ra khi chương trình thay đổi, và đột nhiên việc rò rỉ bộ nhớ nhỏ đang được gọi là mười triệu lần và kết thúc chương trình của bạn ở một nơi khác nên có vấn đề gì không? Nếu nó nằm trong thư viện thì hãy ghi lại lỗi với những người bảo trì thư viện, đừng để rò rỉ vào mã của riêng bạn.


Trong trường hợp đó, tác động của rò rỉ bộ nhớ thay đổi và bạn cần đánh giá lại mức độ ưu tiên của việc cắm rò rỉ.
John Dibling

@ John: Bạn tốt nhất ít nhất là tài liệu rò rỉ sau đó. Ngay cả sau đó, tôi sẽ không tin ai đó không bỏ qua một bình luận nhấp nháy lớn màu đỏ và mã rò rỉ sao chép và dán. Tôi không muốn cho ai đó khả năng làm điều đó ngay từ đầu.
tloach

2

Tôi sẽ trả lời là không.

Về lý thuyết, hệ điều hành sẽ dọn sạch sau bạn nếu bạn để lại một mớ hỗn độn (bây giờ điều đó thật thô lỗ, nhưng vì máy tính không có cảm giác nên có thể chấp nhận được). Nhưng bạn không thể lường trước mọi tình huống có thể xảy ra khi chương trình của bạn được chạy. Do đó (trừ khi bạn có thể tiến hành bằng chứng chính thức về một số hành vi), việc tạo rò rỉ bộ nhớ chỉ là vô trách nhiệm và cẩu thả từ quan điểm chuyên nghiệp.

Nếu một thành phần bên thứ ba rò rỉ bộ nhớ, đây là một lập luận rất mạnh mẽ đối với việc sử dụng nó, không chỉ vì hiệu ứng sắp xảy ra mà còn bởi vì nó cho thấy các lập trình viên làm việc chậm chạp và điều này cũng có thể ảnh hưởng đến các số liệu khác. Bây giờ, khi xem xét các hệ thống cũ, điều này rất khó (xem xét các thành phần duyệt web: theo hiểu biết của tôi, tất cả chúng đều bị rò rỉ bộ nhớ) nhưng nó phải là chuẩn mực.


2

Trong lịch sử, nó có vấn đề trên một số hệ điều hành trong một số trường hợp cạnh. Những trường hợp cạnh có thể tồn tại trong tương lai.

Dưới đây là một ví dụ, trên SunOS trong kỷ nguyên Mặt trời 3, đã xảy ra sự cố nếu một quy trình được sử dụng exec (hoặc truyền thống hơn là fork và sau đó là exec), quy trình mới tiếp theo sẽ thừa hưởng cùng dấu chân bộ nhớ như cha mẹ và nó không thể bị thu hẹp . Nếu một tiến trình cha mẹ được phân bổ 1/2 gig bộ nhớ và không giải phóng nó trước khi gọi exec, tiến trình con sẽ bắt đầu sử dụng 1/2 gigabyte đó (mặc dù nó không được phân bổ). Hành vi này được thể hiện tốt nhất bởi SunTools (hệ thống cửa sổ mặc định của họ), đó là một con heo nhớ. Mỗi ứng dụng sinh ra được tạo ra thông qua fork / exec và kế thừa dấu chân của SunTools, nhanh chóng lấp đầy không gian hoán đổi.


2

Điều này đã được thảo luận về nauseam quảng cáo . Điểm mấu chốt là rò rỉ bộ nhớ là một lỗi và phải được sửa chữa. Nếu một thư viện bên thứ ba làm rò rỉ bộ nhớ, nó khiến người ta tự hỏi có gì khác với nó, phải không? Nếu bạn đang chế tạo một chiếc ô tô, bạn có sử dụng động cơ thỉnh thoảng bị rò rỉ dầu không? Rốt cuộc, ai đó đã tạo ra động cơ, vì vậy đó không phải là lỗi của bạn và bạn không thể sửa nó, phải không?


Nhưng nếu bạn sở hữu một chiếc xe có động cơ thỉnh thoảng bị rò rỉ dầu, bạn có chi tiền để sửa nó hay bạn có để mắt đến mức dầu và thỉnh thoảng nâng nó lên. Câu trả lời phụ thuộc vào tất cả các loại yếu tố.
mỏng

Đây không phải là về việc sở hữu một chiếc xe hơi. Đây là về việc xây dựng một chiếc xe hơi. Nếu bạn nhận được một thư viện của bên thứ ba bị rò rỉ bộ nhớ và bạn hoàn toàn phải sử dụng nó, thì bạn sống với nó. Nhưng nếu bạn là người viết một hệ thống hoặc thư viện, bạn có trách nhiệm đảm bảo rằng nó không có lỗi.
Dima

+1 đối xử với nó như bất kỳ lỗi nào khác. (Điều đó không có nghĩa là "sửa ngay lập tức" trong cuốn sách của tôi, nhưng "chắc chắn cần phải có tiền tố")
peterchen

2

Nói chung, rò rỉ bộ nhớ trong một ứng dụng độc lập không gây tử vong, vì nó được dọn sạch khi chương trình thoát.

Bạn làm gì cho các chương trình Máy chủ được thiết kế để chúng không thoát?

Nếu bạn là loại lập trình viên không thiết kế và triển khai mã trong đó tài nguyên được phân bổ và phát hành chính xác, thì tôi không muốn làm gì với bạn hoặc mã của bạn. Nếu bạn không quan tâm đến việc dọn dẹp bộ nhớ bị rò rỉ, vậy còn ổ khóa của bạn thì sao? Bạn có để chúng treo ngoài đó không? Bạn có để lại một ít các tập tin tạm thời được đặt xung quanh trong các thư mục khác nhau không?

Rò rỉ bộ nhớ đó và để chương trình dọn sạch? Không. Hoàn toàn không. Đó là một thói quen xấu, dẫn đến lỗi, lỗi và nhiều lỗi hơn.

Dọn dẹp sau chính mình. Yo momma không làm việc ở đây nữa.


Tôi đã làm việc trên các chương trình máy chủ cố tình sử dụng các quy trình thay vì các luồng, để rò rỉ bộ nhớ và lỗi phân đoạn gây ra thiệt hại hạn chế.
mỏng

Cách tiếp cận thú vị. Tôi sẽ có một chút lo ngại về các quá trình không thoát ra và tiếp tục ngấu nghiến bộ nhớ.
EvilTeach

2

Theo nguyên tắc chung, nếu bạn bị rò rỉ bộ nhớ mà bạn cảm thấy không thể tránh được, thì bạn cần suy nghĩ kỹ hơn về quyền sở hữu đối tượng.

Nhưng với câu hỏi của bạn, câu trả lời của tôi một cách ngắn gọn là Trong mã sản xuất, vâng. Trong quá trình phát triển, không . Điều này có vẻ ngược, nhưng đây là lý do của tôi:

Trong tình huống bạn mô tả, nơi bộ nhớ được giữ cho đến khi kết thúc chương trình, hoàn toàn ổn khi không phát hành nó. Khi quá trình của bạn thoát, hệ điều hành sẽ dọn sạch bằng mọi cách. Trên thực tế, nó có thể giúp trải nghiệm của người dùng tốt hơn: Trong một trò chơi tôi đã làm việc, các lập trình viên nghĩ rằng sẽ sạch hơn để giải phóng tất cả bộ nhớ trước khi thoát, khiến việc tắt chương trình mất tới nửa phút! Thay đổi nhanh chóng chỉ được gọi là exit () thay vào đó đã làm cho quá trình biến mất ngay lập tức và đưa người dùng trở lại máy tính để bàn nơi anh ta muốn.

Tuy nhiên, bạn nói đúng về các công cụ sửa lỗi: Chúng sẽ phù hợp và tất cả các mặt tích cực giả có thể khiến việc tìm kiếm bộ nhớ thực của bạn bị rò rỉ. Và vì điều đó, luôn luôn viết mã gỡ lỗi giải phóng bộ nhớ và vô hiệu hóa nó khi bạn gửi.

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.