Java에서 객체를 null에 할당하면 가비지 수집에 영향을 줍니까?
null
Java에서 사용되지 않는 객체 참조를 할당하면 가비지 수집 프로세스가 측정 가능한 방식으로 개선됩니까?
Java (및 C #)에 대한 경험을 통해 가상 머신 또는 JIT 컴파일러를 시도하고 능가하는 것이 직관적이지 않은 경우가 많지만 동료들이이 방법을 사용하는 것을 보았으며 이것이 좋은 방법인지 궁금합니다. 아니면 그 부두 프로그래밍 미신 중 하나?
일반적으로 아닙니다.
그러나 모든 것들이 그렇듯이 상황에 따라 다릅니다. 요즘 Java의 GC는 매우 훌륭하며 더 이상 도달 할 수없는 즉시 모든 것을 정리해야합니다. 이것은 지역 변수에 대한 메서드를 떠난 직후와 클래스 인스턴스가 더 이상 필드에 대해 참조되지 않을 때입니다.
그렇지 않으면 참조 된 상태로 유지된다는 것을 알고있는 경우에만 명시 적으로 null이 필요합니다. 예를 들어 주변에 보관되는 배열입니다. 더 이상 필요하지 않은 경우 배열의 개별 요소를 null로 지정할 수 있습니다.
예를 들어 ArrayList의 다음 코드는 다음과 같습니다.
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
또한 객체를 명시 적으로 null로 설정하면 참조가 남아 있지 않는 한 자연스럽게 범위를 벗어나는 것보다 더 빨리 객체가 수집되지 않습니다.
양자 모두:
void foo() {
Object o = new Object();
/// do stuff with o
}
과:
void foo() {
Object o = new Object();
/// do stuff with o
o = null;
}
기능적으로 동일합니다.
좋은 기사는 오늘의 코딩 공포 입니다.
GC의 작업 방식은 포인터가없는 객체를 찾는 것입니다. 검색 영역은 힙 / 스택 및 기타 공간입니다. 따라서 변수를 null로 설정하면 실제 개체는 이제 누구도 가리 키지 않으므로 GC가 될 수 있습니다.
그러나 GC가 정확한 순간에 실행되지 않을 수 있으므로 실제로는 아무것도 구매하지 않을 수 있습니다. 그러나 방법이 상당히 길다면 (실행 시간 측면에서) GC가 해당 객체를 수집 할 가능성이 높아 지므로 그만한 가치가 있습니다.
이 문제는 코드 최적화로도 복잡 할 수 있습니다. 변수를 null로 설정 한 후 변수를 사용하지 않으면 값을 null로 설정하는 줄을 제거하는 것이 안전한 최적화입니다 (실행할 명령이 하나 적음). 따라서 실제로 개선되지 않을 수도 있습니다.
요약하자면 도움이 될 수는 있지만 결정적이지는 않습니다 .
내 경험상, 사람들은 종종 필요가 아닌 편집증 때문에 참고 문헌을 무효화합니다. 다음은 빠른 지침입니다.
객체 A를 참조가 B 객체 경우 와 더 이상이 참조를 필요로하지 와 객체 A가 가비지 컬렉션에 적합하지 않습니다 당신은 명시 적으로 필드를 null로해야한다. 둘러싸고있는 객체가 어쨌든 가비지 수집을 받고 있다면 필드를 null 아웃 할 필요가 없습니다. dispose () 메서드에서 필드를 무효화하는 것은 거의 항상 쓸모가 없습니다.
메서드에서 생성 된 개체 참조를 null로 만들 필요가 없습니다. 메소드가 종료되면 자동으로 지워집니다. 이 규칙의 예외는 매우 긴 메서드 또는 대규모 루프에서 실행 중이고 메서드가 끝나기 전에 일부 참조를 지워야하는 경우입니다. 다시 말하지만 이러한 경우는 매우 드뭅니다.
대부분의 경우 참조를 무효화 할 필요가 없습니다. 가비지 수집기를 능가하려는 것은 쓸모가 없습니다. 비효율적이고 읽을 수없는 코드로 끝날 것입니다.
적어도 자바에서는 부두 프로그래밍이 아닙니다. 다음과 같은 것을 사용하여 Java에서 객체를 만들 때
Foo bar = new Foo();
두 가지 작업을 수행합니다. 첫째, 객체에 대한 참조를 생성하고 둘째, Foo 객체 자체를 생성합니다. 해당 참조 또는 다른 참조가 존재하는 한 특정 개체를 gc'd 할 수 없습니다. 그러나 해당 참조에 null을 할당하면 ...
bar = null ;
다른 객체에 대한 참조가 없다고 가정하면 다음 번 가비지 수집기가 지나갈 때 gc에서 해제되어 사용할 수 있습니다.
때에 따라 다르지.
일반적으로 개체에 대한 참조를 짧게 유지하면 수집 속도가 빨라집니다.
메서드를 실행하는 데 2 초가 걸리고 메서드 실행 1 초 후에 더 이상 개체가 필요하지 않은 경우 해당 참조를 지우는 것이 좋습니다. GC가 1 초 후에도 객체를 참조하면 다음 번에 1 분 정도 후에 확인할 수 있습니다.
어쨌든, 기본적으로 모든 참조를 null로 설정하는 것은 저에게 조기 최적화이며 메모리 소비를 현저하게 감소시키는 특별한 드문 경우가 아니면 아무도 수행해서는 안됩니다.
변수가 범위를 벗어나도록하는 대신 명시 적으로 null에 대한 참조를 설정하는 것은 보유한 개체가 매우 크지 않는 한 가비지 수집기에 도움이되지 않습니다. 작업을 마치는 즉시 null로 설정하는 것이 좋습니다.
일반적으로 참조를 null로 설정하는 것은이 개체가 완전히 완료되었으며 더 이상 염려하지 않아야하는 코드의 READER를 의미합니다.
추가 중괄호 세트를 넣어 더 좁은 범위를 도입하여 유사한 효과를 얻을 수 있습니다.
{
int l;
{ // <- here
String bigThing = ....;
l = bigThing.length();
} // <- and here
}
이렇게하면 중첩 된 중괄호를 떠난 직후에 bigThing이 가비지 수집 될 수 있습니다.
public class JavaMemory {
private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);
public void f() {
{
byte[] data = new byte[dataSize];
//data = null;
}
byte[] data2 = new byte[dataSize];
}
public static void main(String[] args) {
JavaMemory jmp = new JavaMemory();
jmp.f();
}
}
위의 프로그램은 OutOfMemoryError
. 주석을 제거 data = null;
하면 OutOfMemoryError
문제가 해결됩니다. 항상 사용하지 않는 변수를 null로 설정하는 것이 좋습니다.
한 번은 화상 회의 응용 프로그램을 작업하고 있었는데 더 이상 개체가 필요하지 않 자마자 null 참조에 시간을 할애했을 때 성능에 큰 큰 차이가 있음을 알았습니다. 이것은 2003-2004 년이었고 GC가 그 이후로 더 똑똑해 졌다고 상상할 수 있습니다. 제 경우에는 매초마다 수백 개의 개체가오고가는 개체가 있었기 때문에 GC가 주기적으로 시작될 때 발견했습니다. 그러나 객체를 null로 지정하면 GC가 내 응용 프로그램을 일시 중지하는 것을 중지했습니다.
So it depends on what your doing...
Yes.
From "The Pragmatic Programmer" p.292:
By setting a reference to NULL you reduce the number of pointers to the object by one ... (which will allow the garbage collector to remove it)
I assume the OP is referring to things like this:
private void Blah()
{
MyObj a;
MyObj b;
try {
a = new MyObj();
b = new MyObj;
// do real work
} finally {
a = null;
b = null;
}
}
In this case, wouldn't the VM mark them for GC as soon as they leave scope anyway?
Or, from another perspective, would explicitly setting the items to null cause them to get GC'd before they would if they just went out of scope? If so, the VM may spend time GC'ing the object when the memory isn't needed anyway, which would actually cause worse performance CPU usage wise because it would be GC'ing more earlier.
"It depends"
I do not know about Java but in .net (C#, VB.net...) it is usually not required to assign a null when you no longer require a object.
However note that it is "usually not required".
By analyzing your code the .net compiler makes a good valuation of the life time of the variable...to accurately tell when the object is not being used anymore. So if you write obj=null it might actually look as if the obj is still being used...in this case it is counter productive to assign a null.
There are a few cases where it might actually help to assign a null. One example is you have a huge code that runs for long time or a method that is running in a different thread, or some loop. In such cases it might help to assign null so that it is easy for the GC to know its not being used anymore.
There is no hard & fast rule for this. Going by the above place null-assigns in your code and do run a profiler to see if it helps in any way. Most probably you might not see a benefit.
If it is .net code you are trying to optimize, then my experience has been that taking good care with Dispose and Finalize methods is actually more beneficial than bothering about nulls.
Some references on the topic:
http://blogs.msdn.com/csharpfaq/archive/2004/03/26/97229.aspx
http://weblogs.asp.net/pwilson/archive/2004/02/20/77422.aspx
Even if nullifying the reference were marginally more efficient, would it be worth the ugliness of having to pepper your code with these ugly nullifications? They would only be clutter and obscure the intent code that contains them.
Its a rare codebase that has no better candidate for optimisation than trying to outsmart the Garbage collector (rarer still are developers who succeed in outsmarting it). Your efforts will most likely be better spent elsewhere instead, ditching that crufty Xml parser or finding some opportunity to cache computation. These optimisations will be easier to quantify and don't require you dirty up your codebase with noise.
In the future execution of your program, the values of some data members will be used to computer an output visible external to the program. Others might or might not be used, depending on future (And impossible to predict) inputs to the program. Other data members might be guaranteed not to be used. All resources, including memory, allocated to those unused data are wasted. The job of the garbage collector (GC) is to eliminate that wasted memory. It would be disastrous for the GC to eliminate something that was needed, so the algorithm used might be conservative, retaining more than the strict minimum. It might use heuristic optimizations to improve its speed, at the cost of retaining some items that are not actually needed. There are many potential algorithms the GC might use. Therefore it is possible that changes you make to your program, and which do not affect the correctness of your program, might nevertheless affect the operation of the GC, either making it run faster to do the same job, or to sooner identify unused items. So this kind of change, setting an unusdd object reference to null
, in theory is not always voodoo.
Is it voodoo? There are reportedly parts of the Java library code that do this. The writers of that code are much better than average programmers and either know, or cooperate with, programmers who know details of the garbage collector implementations. So that suggests there is sometimes a benefit.
'Nice programing' 카테고리의 다른 글
Entity Framework가 자식 개체를 저장 / 삽입하지 못하도록하려면 어떻게해야합니까? (0) | 2020.10.05 |
---|---|
일반 프로토콜을 변수 유형으로 사용하는 방법 (0) | 2020.10.05 |
ContextMenuStrip이 사용 된 컨트롤 확인 (0) | 2020.10.05 |
JavaScript로 SVG의 Z 인덱스 / 레이어를 변경할 수 있습니까? (0) | 2020.10.04 |
코드에서 바인딩을 설정하는 방법은 무엇입니까? (0) | 2020.10.04 |