.NET에서 메모리 누수가없는 이유는 무엇입니까?
안전하지 않은 코드를 무시하면 .NET은 메모리 누수가 발생할 수 없습니다. 나는 많은 전문가들로부터 끝없이 이것을 읽고 그것을 믿습니다. 그러나 나는 이것이 왜 그런지 이해하지 못합니다.
프레임 워크 자체는 C ++로 작성되었고 C ++는 메모리 누수에 취약하다는 것이 제 이해입니다.
- 기본 프레임 워크가 너무 잘 작성되어 내부 메모리 누수의 가능성이 전혀 없습니까?
- 프레임 워크의 코드 내에 자체적으로 메모리 누수를 스스로 관리하고 치료하는 것이 있습니까?
- 내가 고려하지 않은 다른 답변입니까?
여기에 이미 좋은 답변이 있지만 한 가지 추가 사항을 언급하고 싶습니다. 구체적인 질문을 다시 자세히 살펴 보겠습니다.
프레임 워크 자체는 C ++로 작성되었고 C ++는 메모리 누수에 취약하다는 것이 제 이해입니다.
- 기본 프레임 워크가 너무 잘 작성되어 내부 메모리 누수의 가능성이 전혀 없습니까?
- 프레임 워크의 코드 내에 자체적으로 메모리 누수를 스스로 관리하고 치료하는 것이 있습니까?
- 내가 고려하지 않은 다른 답변입니까?
열쇠는 여기를 구분하는 것입니다 귀하의 코드와 그 코드입니다. 당신에 의존하는 경우 닷넷 프레임 워크 (자바, 이동, 파이썬, 및 기타 쓰레기 수집 언어) 그 약속 자신의 코드, 당신의 코드하지 않습니다 누출 메모리 ... 전통적인 의미에서 적어도. 일부 개체가 예상대로 해제되지 않는 상황에 처할 수 있지만 이러한 경우는 프로그램에서 개체에 여전히 도달 할 수 있기 때문에 기존 메모리 누수와 미묘하게 다릅니다.
이것이 당신이 만든 프로그램이 전통적인 메모리 누수를 전혀 가질 수 없다고 말하는 것과 같은 것이 아니라는 것을 올바르게 이해했기 때문에 혼란스러워합니다. 아직 버그가있을 수 있습니다 자신의 메모리 누수 코드입니다.
이제 스스로에게 물어봐야합니다. 자신의 코드를 신뢰 하시겠습니까, 아니면 코드를 신뢰 하시겠습니까? 여기에서 그들의 코드는 원래 개발자 (당신과 마찬가지로)에 의해 테스트 될뿐만 아니라, 당신과 같은 수천 (아마도 수백만)의 다른 프로그래머들이 매일 사용함으로써 전투로 강화된다는 것을 명심하십시오. 중요한 메모리 누수 문제는 가장 먼저 식별되고 수정되는 것입니다. 다시 말하지만, 불가능하다고 말하는 것이 아닙니다. 일반적으로 자신의 코드보다 자신의 코드를 신뢰하는 것이 일반적으로 더 나은 아이디어입니다.
따라서 여기에서 정답은 첫 번째 제안의 변형이라는 것입니다.
기본 프레임 워크가 너무 잘 작성되어 내부 메모리 누수의 가능성이 전혀 없습니까?
가능성이 없다는 것이 아니라 직접 관리하는 것보다 훨씬 안전합니다. 프레임 워크에서 알려진 누출에 대해서는 확실히 알지 못합니다 .
.NET 에는 메모리 누수 가 있을 수 있습니다.
대부분 사람들은 객체 (또는 전체 객체주기)를 제거 할 수있는시기를 결정하는 가비지 수집기를 참조합니다. 이것은 메모리를 할당하고 나중에 해제하지 않는 것을 의미 하는 고전적인 c 및 C ++ 스타일 메모리 누수를 방지합니다 .
그러나 많은 경우 프로그래머는 객체가 여전히 댕글 링 참조를 가지고 있고 가비지 수집되지 않아 메모리 누수가 발생한다는 사실을 깨닫지 못합니다.
이는 일반적으로 이벤트가 등록 (사용 +=)되었지만 나중에 등록 취소되지 않은 경우뿐만 아니라 비 관리 코드에 액세스 (파일 시스템 또는 데이터베이스 연결과 같은 기본 시스템 리소스를 사용하는 개체 사용)하고 리소스를 적절하게 폐기하지 않는 경우에도 발생합니다. .
Microsoft 설명서, 특히 " CLR에서 메모리 누수 확인 "을 검토 한 후 Microsoft는 응용 프로그램 내에서 안전하지 않은 코드를 구현하지 않는 한 메모리 누수가 발생할 수 없다는 진술을합니다.
이제 그들은 또한 인식 된 메모리 누수 개념을 지적하거나 주석에서 지적했듯이 "리소스 누수"라는 개념을 지적합니다. 이는 느린 참조가 있고 적절하게 처리되지 않은 개체를 사용하는 것입니다. 이는 IO 개체, 데이터 세트, GUI 요소 등에서 발생할 수 있습니다. .NET으로 작업 할 때 일반적으로 "메모리 누수"와 동일하지만 전통적인 의미에서 누수는 아닙니다.
가비지 수집으로 인해 정기적 인 메모리 누수가 발생할 수 없습니다 (안전하지 않은 코드 및 P / Invoke와 같은 특수한 경우 제외). 그러나 의도하지 않게 참조를 영원히 유지하여 효과적으로 메모리를 누수 할 수 있습니다 .
편집하다
지금까지 진짜 누출에 대해 본 가장 좋은 예는 이벤트 핸들러 + = 실수입니다.
편집하다
실수에 대한 설명과 거의 진짜 누출이 아닌 진짜 누출로 인정되는 조건에 대한 설명은 아래를 참조하십시오.
다음은 안전하지 않은 / 핀 보크를 포함하지 않고 이벤트 처리기도 포함하지 않는 .NET의 메모리 누수 예입니다.
네트워크를 통해 일련의 메시지를 수신하고 처리하는 백그라운드 서비스를 작성한다고 가정 해보십시오. 그래서 그들을 담을 수업을 만듭니다.
class Message
{
public Message(int id, string text) { MessageId = id; Text = text; }
public int MessageId { get; private set; }
public string Text { get; private set; }
}
좋아, 지금까지 너무 좋아. 나중에 처리를 수행 할 때 사용 가능한 이전 메시지에 대한 참조가 있으면 시스템의 일부 요구 사항이 더 쉬워 질 수 있음을 알게됩니다. 이것을 원하는 데는 여러 가지 이유가있을 수 있습니다.
따라서 새 속성을 추가합니다.
class Message
{
...
public Message PreviousMessage { get; private set; }
...
}
그리고 그것을 설정하는 코드를 작성합니다. 그리고 물론, 메인 루프의 어딘가에 마지막 메시지를 따라 잡을 변수가 있어야합니다.
Message lastMessageReceived;
그런 다음 서비스가 폭격 한 것보다 며칠 늦게 발견합니다. 사용 가능한 모든 메모리가 쓸모없는 메시지의 긴 체인으로 가득 차 있기 때문입니다.
이 사람이 ANTS .NET 프로파일 러를 사용하여 발견 한 다른 메모리 누수는 다음과 같습니다. http://www.simple-talk.com/dotnet/.net-tools/tracing-memory-leaks-in-.net-applications-with-ants -프로파일 러 /
.NET 런타임 환경 (CLR)과 같은 소프트웨어를 작성하는 것이 가능하다고 생각하는데, 충분히주의하면 메모리가 누출되지 않습니다. 마이크로 소프트가 수시로 Windows Update를 통해 .NET 프레임 워크에 문제 업데이트를 수행하기 때문에, 나는 꽤 확실이 있다고 해요 입니다 가끔 버그에도 CLR에서.
모든 소프트웨어는 메모리 누수를 일으킬 수 있습니다.
그러나 다른 사람들이 이미 지적했듯이 다른 종류의 메모리 누수가 있습니다. 가비지 수집기가 "고전적인"메모리 누수를 처리하지만, 예를 들어 소위 관리되지 않는 리소스 (예 : 데이터베이스 연결, 열린 파일, GUI 요소 등) 를 해제하는 문제가 여전히 있습니다. 그것이 IDisposable인터페이스가 들어오는 곳 입니다.
또한 최근에 .NET-COM interop 설정 에서 메모리 누수가 발생할 수 있음을 발견했습니다 . COM 구성 요소는 참조 횟수를 사용하여 해제 할 수있는시기를 결정합니다. .NET은 여기에 정적 System.Runtime.InteropServices.Marshal클래스 를 통해 영향을받을 수있는 또 다른 참조 계산 메커니즘을 추가합니다 .
결국 .NET 프로그램에서도 리소스 관리에 대해주의해야합니다.
.NET 코드에서 절대적으로 메모리 누수가 발생할 수 있습니다. 일부 개체는 경우에 따라 자체 루트를 수행합니다 (일반적으로 IDisposable). Dispose()이 경우 개체 호출 에 실패하면 참조 할 방법이없는 할당 된 개체와 함께 실제 C / C ++ 스타일 메모리 누수가 발생합니다.
경우에 따라 특정 타이머 클래스가 이러한 동작을 가질 수 있습니다.
자체 일정을 조정할 수있는 비동기 작업이있는 경우 누수가 발생할 수 있습니다. 비동기 작업은 일반적으로 콜백 객체를 루팅하여 수집을 방지합니다. 실행하는 동안 개체는 실행중인 스레드에 의해 루트가되고 새로 예약 된 작업이 개체를 다시 루트합니다.
다음은 System.Threading.Timer.
public class Test
{
static public int Main(string[] args)
{
MakeFoo();
GC.Collect();
GC.Collect();
GC.Collect();
System.Console.ReadKey();
return 0;
}
private static void MakeFoo()
{
Leaker l = new Leaker();
}
}
internal class Leaker
{
private Timer t;
public Leaker()
{
t = new Timer(callback);
t.Change(1000, 0);
}
private void callback(object state)
{
System.Console.WriteLine("Still alive!");
t.Change(1000, 0);
}
}
Much like GlaDOS, the Leaker object will be indefinitely "still alive" - yet, there is no way to access the object (except internally, and how can the object know when it's not referenced anymore?)
If you aren't referring to applications using .NET, which these answers discuss very well, but are actually referring to the runtime itself, then it technically can have memory leaks, but at this point the implementation of the garbage collector is probably nearly bug-free. I have heard of one case in which a bug was found where something in the runtime, or maybe just in the standard libraries, had a memory leak. But I don't remember what it was (something very obscure), and I don't think I would be able to find it again.
Well .NET has a garbage collector to clean things up when it sees fit. This is what separates it from other unmanaged languages.
But .NET can have memory leaks. GDI leaks are common among Windows Forms applications, for example. One of the applications I've helped develop experiences this on a regular basis. And when the employees in the office use multiple instances of it all day long it's not uncommon for them to hit the 10,000 GDI object limit inherent to Windows.
One major source of C/C++ memory leaks that effectively doesn't exist in .Net is when to deallocate shared memory
The following is from a Brad Abrams led class on Designing .NET Class Libraries
"Well, the first point is, of course, there are no memory leaks, right? No? There are still memory leaks? Well, there is a different kind of memory leak. How about that? So the kind of memory leak that we don’t have is, in the old world, you used to malloc some memory and then forget to do a free or add ref and forget to do a release, or whatever the pair is. And in the new world, the garbage collector ultimately owns all the memory, and the garbage collector will free that stuff when there are no longer any references. But there can still sort of be leaks, right? What are the sort of leaks? Well, if you keep a reference to that object alive, then the garbage collector can’t free that. So lots of times, what happens is you think you’ve gotten rid of that whole graph of objects, but there’s still one guy holding on to it with a reference, and then you’re stuck. The garbage collector can’t free that until you drop all your references to it.
The other one, I think, is a big issue. No memory ownership issue. If you go read the WIN32 API documentation, you’ll see, okay, I allocate this structure first and pass it in and then you populate it, and then I free it. Or do I tell you the size and you allocate it and then I free it later or you know, there are all these debates going on about who owns that memory and where it’s supposed to be freed. And many times, developers just give up on that and say, “Okay, whatever. Well, it’ll be free when the application shuts down,” and that’s not such a good plan.
In our world, the garbage collector owns all the managed memory, so there’s no memory ownership issue, whether you created it and pass it to the application, the application creates and you start using it. There’s no problem with any of that, because there’s no ambiguity. The garbage collector owns it all. "
Remember, the difference between a cache and a memory leak is policy. If your cache has a bad policy (or worse, none) for removing objects, it is indistinguishable from a memory leak.
This reference shows how leaks can happen in .Net using weak event patterns. http://msdn.microsoft.com/en-us/library/aa970850.aspx
.NET can have memory leaks but it does a lot to help you avoid them. All reference type objects are allocated from a managed heap which tracks what objects are currently being used (value types are usually allocated on the stack). Whenever a new reference type object is created in .NET, it is allocated from this managed heap. The garbage collector is responsible for periodically running and freeing up any object that is no longer used (no longer being referenced by anything else in the application).
Jeffrey Richter's book CLR via C# has a good chapter on how memory is managed in .NET.
The best example I've found was actually from Java, but the same principle applies to C#.
We were reading in text files that consisted of many long lines (each line was a few MB in heap). From each file, we searched for a few key substrings and kept just the substrings. After processing a few hundred text files, we ran out of memory.
It turned out that string.substring(...) would keep a reference to the original long string... even though we kept only 1000 characters or so, those sub-strings would still use several MB of memory each. In effect, we kept the contents of every file in memory.
This is an example of a dangling reference that resulted in leaked memory. The substring method was trying to reuse objects, but ended up wasting memory.
Edit: Not sure if this specific problem plagues .NET. The idea was to illustrate an actual design/optimization performed in a garbage collected language that was, in most cases, smart and useful, but can result in a unwanted memory usage.
What about if you are using a managed dll but the dll contians unsafe code? I know this is spliting hairs, but if you dont have the source code, then from yourr point of view, you are only using managed code but you can still leak.
참고URL : https://stackoverflow.com/questions/2526037/why-can-net-not-have-memory-leaks
'IT Share you' 카테고리의 다른 글
| Android는 홈 화면에 바로 가기를 만듭니다. (0) | 2020.12.13 |
|---|---|
| Gradle 오류 : 지원되는 최소 Gradle 버전은 3.3입니다. (0) | 2020.12.13 |
| pip install PIL은 virtualenv에 설치되지 않습니다. (0) | 2020.12.13 |
| Spring Boot-실행중인 포트를 얻는 방법 (0) | 2020.12.13 |
| 실행중인 모든 스레드를 종료하는 방법은 무엇입니까? (0) | 2020.12.13 |