Java 용 소멸자가 있습니까?
Java 용 소멸자가 있습니까? 이에 대한 문서를 찾을 수없는 것 같습니다. 없는 경우 어떻게 동일한 효과를 얻을 수 있습니까?
내 질문을 더 구체적으로 설명하기 위해 데이터를 다루는 애플리케이션을 작성 중이며 사양에는 애플리케이션을 방금 시작된 원래 상태로 되 돌리는 '재설정'버튼이 있어야한다고 나와 있습니다. 그러나 모든 데이터는 애플리케이션을 닫거나 리셋 버튼을 누르지 않는 한 '라이브'상태 여야합니다.
일반적으로 C / C ++ 프로그래머이기 때문에 구현하기가 쉽지 않을 것이라고 생각했습니다. (따라서 마지막으로 구현할 계획이었습니다.) 모든 '재설정 가능'객체가 동일한 클래스에 있도록 프로그램을 구성하여 재설정 버튼을 누르면 모든 '라이브'객체를 파괴 할 수 있습니다.
데이터를 역 참조하고 가비지 수집기가 수집 할 때까지 기다리는 것이 전부라면 사용자가 반복적으로 데이터를 입력하고 재설정 버튼을 누르면 메모리 누수가 발생하지 않을까요? 나는 또한 자바가 언어로서 꽤 성숙하기 때문에 이런 일이 일어나지 않도록하거나이 문제를 적절하게 다룰 수있는 방법이 있어야한다고 생각했다.
Java는 가비지 수집 언어이기 때문에 객체가 언제 파괴 될지 예측할 수 없습니다. 따라서 소멸자와 직접적으로 동등한 것은 없습니다.
라는 상속 된 메서드 finalize
가 있지만 가비지 수집기의 재량에 따라 전적으로 호출됩니다. 따라서 명시 적으로 정리해야하는 클래스의 경우 규칙은 close 메서드 를 정의하고 상태 확인을 위해서만 finalize를 사용하는 것입니다 (즉, close 가 호출되지 않은 경우 지금 수행하고 오류를 기록합니다).
최근 에 finalize 에 대한 심층 토론을 불러 일으킨 질문 이 있었 으므로 필요한 경우 더 깊이를 제공해야합니다.
try-with-resources 문을 살펴 보십시오 . 예를 들면 :
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
System.out.println(br.readLine());
} catch (Exception e) {
...
} finally {
...
}
여기서 더 이상 필요하지 않은 리소스는 BufferedReader.close()
메서드 에서 해제됩니다 . AutoCloseable
유사한 방식으로 구현 하고 사용할 수있는 고유 한 클래스를 만들 수 있습니다 .
이 문장은 finalize
코드 구조화 측면에서 보다 더 제한적 이지만 동시에 코드를 이해하고 유지 관리하기가 더 간단합니다. 또한 finalize
응용 프로그램이 실행되는 동안 메서드가 호출 된다는 보장도 없습니다 .
아니, 여기에 소멸자가 없습니다. 그 이유는 모든 Java 개체가 힙 할당되고 가비지 수집되기 때문입니다. 명시적인 할당 해제 (예 : C ++의 삭제 연산자)가 없으면 실제 소멸자를 구현하는 현명한 방법이 없습니다.
Java는 종료자를 지원하지만 소켓, 파일 핸들, 창 핸들 등과 같은 기본 리소스에 대한 핸들을 보유하는 객체에 대한 보호 수단으로 만 사용됩니다. 가비지 수집기가 종료 자없이 객체를 수집 할 때 단순히 메모리를 표시합니다. 지역은 무료이며 그게 다입니다. 객체에 종료자가 있으면 먼저 임시 위치에 복사 된 다음 (여기서 가비지 수집 중임을 기억하십시오) 종료 대기 대기열에 넣은 다음 종료 자 스레드가 매우 낮은 우선 순위로 대기열을 폴링합니다. 종료자를 실행합니다.
응용 프로그램이 종료되면 보류중인 개체가 완료 될 때까지 기다리지 않고 JVM이 중지되므로 종료자가 실행될 것이라는 보장은 거의 없습니다.
finalize () 메서드를 사용 하지 않아야합니다. 이는 자원 정리를위한 신뢰할 수있는 메커니즘이 아니며이를 남용하여 가비지 수집기에 문제를 일으킬 수 있습니다.
리소스 해제와 같이 객체에서 할당 해제 호출이 필요한 경우 명시 적 메서드 호출을 사용합니다. 이 규칙은 기존 API (예 : Closeable , Graphics.dispose () , Widget.dispose () ) 에서 볼 수 있으며 일반적으로 try / finally를 통해 호출됩니다.
Resource r = new Resource();
try {
//work
} finally {
r.dispose();
}
삭제 된 객체를 사용하려고하면 런타임 예외가 발생해야합니다 ( IllegalStateException 참조 ).
편집하다:
데이터를 역 참조하고 가비지 수집기가 수집 할 때까지 기다리는 것이 전부라면 사용자가 반복적으로 데이터를 입력하고 재설정 버튼을 누르면 메모리 누수가 발생하지 않을까요?
일반적으로해야 할 일은 객체를 역 참조하는 것입니다. 적어도 이것이 작동해야하는 방식입니다. 가비지 콜렉션이 걱정된다면 Java SE 6 HotSpot [tm] Virtual Machine Garbage Collection Tuning (또는 JVM 버전에 해당하는 문서)을 확인하십시오.
Java 1.7이 릴리스되면 이제 try-with-resources
블록 을 사용하는 추가 옵션이 있습니다. 예를 들면
public class Closeable implements AutoCloseable {
@Override
public void close() {
System.out.println("closing...");
}
public static void main(String[] args) {
try (Closeable c = new Closeable()) {
System.out.println("trying...");
throw new Exception("throwing...");
}
catch (Exception e) {
System.out.println("catching...");
}
finally {
System.out.println("finalizing...");
}
}
}
If you execute this class, c.close()
will be executed when the try
block is left, and before the catch
and finally
blocks are executed. Unlike in the case of the finalize()
method, close()
is guaranteed to be executed. However, there is no need of executing it explicitly in the finally
clause.
I fully agree to other answers, saying not to rely on the execution of finalize.
In addition to try-catch-finally blocks, you may use Runtime#addShutdownHook (introduced in Java 1.3) to perform final cleanups in your program.
That isn't the same as destructors are, but one may implement a shutdown hook having listener objects registered on which cleanup methods (close persistent database connections, remove file locks, and so on) can be invoked - things that would normally be done in destructors. Again - this is not a replacement for destructors but in some cases, you can approach the wanted functionality with this.
The advantage of this is having deconstruction behavior loosely coupled from the rest of your program.
No, java.lang.Object#finalize
is the closest you can get.
However, when (and if) it is called, is not guaranteed.
See: java.lang.Runtime#runFinalizersOnExit(boolean)
First, note that since Java is garbage-collected, it is rare to need to do anything about object destruction. Firstly because you don't usually have any managed resources to free, and secondly because you can't predict when or if it will happen, so it's inappropriate for things that you need to occur "as soon as nobody is using my object any more".
You can be notified after an object has been destroyed using java.lang.ref.PhantomReference (actually, saying it has been destroyed may be slightly inaccurate, but if a phantom reference to it is queued then it's no longer recoverable, which usually amounts to the same thing). A common use is:
- Separate out the resource(s) in your class that need to be destructed into another helper object (note that if all you're doing is closing a connection, which is a common case, you don't need to write a new class: the connection to be closed would be the "helper object" in that case).
- When you create your main object, create also a PhantomReference to it. Either have this refer to the new helper object, or set up a map from PhantomReference objects to their corresponding helper objects.
- After the main object is collected, the PhantomReference is queued (or rather it may be queued - like finalizers there is no guarantee it ever will be, for example if the VM exits then it won't wait). Make sure you're processing its queue (either in a special thread or from time to time). Because of the hard reference to the helper object, the helper object has not yet been collected. So do whatever cleanup you like on the helper object, then discard the PhantomReference and the helper will eventually be collected too.
There is also finalize(), which looks like a destructor but doesn't behave like one. It's usually not a good option.
I am sorry if this strays from the main topic, but java.util.Timer (SE6) documentation says:
"After the last live reference to a Timer object goes away and all outstanding tasks have completed execution, the timer's task execution thread terminates gracefully (and becomes subject to garbage collection). However, this can take arbitrarily long to occur. By default, the task execution thread does not run as a daemon thread, so it is capable of keeping an application from terminating. If a caller wants to terminate a timer's task execution thread rapidly, the caller should invoke the timer's cancel method..."
I would like to call cancel upon the class owning the Timer losing its last reference(or immeditalesky before). Here a reliable destructor could do that for me. The comments above indicate that finally is a poor choice, but is there an elegant solution? That business of "...capable of keeping an application from terminating..." is not appealing.
The finalize()
function is the destructor.
However, it should not be normally used because it is invoked after the GC and you can't tell when that will happen (if ever).
Moreover, it takes more than one GC to deallocate objects that have finalize()
.
You should try to clean up in the logical places in your code using the try{...} finally{...}
statements!
I agree with most of the answers.
You should not depend fully on either finalize
or ShutdownHook
The JVM does not guarantee when this
finalize()
method will be invoked.finalize()
gets called only once by GC thread. If an object revives itself from finalizing method, thenfinalize
will not be called again.In your application, you may have some live objects, on which garbage collection is never invoked.
Any
Exception
that is thrown by the finalizing method is ignored by the GC threadSystem.runFinalization(true)
andRuntime.getRuntime().runFinalization(true)
methods increase the probability of invokingfinalize()
method but now these two methods have been deprecated. These methods are very dangerous due to lack of thread safety and possible deadlock creation.
public void addShutdownHook(Thread hook)
Registers a new virtual-machine shutdown hook.
The Java virtual machine shuts down in response to two kinds of events:
- The program exits normally, when the last non-daemon thread exits or when the exit (equivalently,
System.exit
) method is invoked, or - The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
- A shutdown hook is simply an initialized but non-started thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. When all the hooks have finished it will then run all uninvoked finalizers if finalization-on-exit has been enabled.
- Finally, the virtual machine will halt. Note that daemon threads will continue to run during the shutdown sequence, as will non-daemon threads if the shutdown was initiated by invoking the exit method.
Shutdown hooks should also finish their work quickly. When a program invokes exit the expectation is that the virtual machine will promptly shut down and exit.
But even Oracle documentation quoted that
In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly
This occurs when the virtual machine is terminated externally, for example with the SIGKILL
signal on Unix or the TerminateProcess
call on Microsoft Windows. The virtual machine may also abort if a native method goes awry by, for example, corrupting internal data structures or attempting to access nonexistent memory. If the virtual machine aborts then no guarantee can be made about whether or not any shutdown hooks will be run.
Conclusion : use try{} catch{} finally{}
blocks appropriately and release critical resources in finally(}
block. During release of resources in finally{}
block, catch Exception
and Throwable
.
If it's just memory you are worried about, don't. Just trust the GC it does a decent job. I actually saw something about it being so efficient that it could be better for performance to create heaps of tiny objects than to utilize large arrays in some instances.
Perhaps you can use a try ... finally block to finalize the object in the control flow at which you are using the object. Of course it doesn't happen automatically, but neither does destruction in C++. You often see closing of resources in the finally block.
There is a @Cleanup annotation in Lombok that mostly resembles C++ destructors:
@Cleanup
ResourceClass resource = new ResourceClass();
When processing it (at compilation time), Lombok inserts appropriate try-finally
block so that resource.close()
is invoked, when execution leaves the scope of the variable. You can also specify explicitly another method for releasing the resource, e.g. resource.dispose()
:
@Cleanup("dispose")
ResourceClass resource = new ResourceClass();
The closest equivalent to a destructor in Java is the finalize() method. The big difference to a traditional destructor is that you can't be sure when it'll be called, since that's the responsibility of the garbage collector. I'd strongly recommend carefully reading up on this before using it, since your typical RAIA patterns for file handles and so on won't work reliably with finalize().
If you're writing a Java Applet, you can override the Applet "destroy()" method. It is...
* Called by the browser or applet viewer to inform * this applet that it is being reclaimed and that it should destroy * any resources that it has allocated. The stop() method * will always be called before destroy().
Obviously not what you want, but might be what other people are looking for.
Though there have been considerable advancements in Java's GC technology, you still need to be mindful of your references. Numerous cases of seemingly trivial reference patterns that are actually rats nests under the hood come to mind.
From your post it doesn't sound like you're trying to implement a reset method for the purpose of object reuse (true?). Are your objects holding any other type of resources that need to be cleaned up (i.e., streams that must be closed, any pooled or borrowed objects that must be returned)? If the only thing you're worried about is memory dealloc then I would reconsider my object structure and attempt to verify that my objects are self contained structures that will be cleaned up at GC time.
Just thinking about the original question... which, I think we can conclude from all the other learned answers, and also from Bloch's essential Effective Java, item 7, "Avoid finalizers", seeks the solution to a legitimate question in a manner which is inappropriate to the Java language...:
... wouldn't a pretty obvious solution to do what the OP actually wants be to keep all your objects which need to be reset in a sort of "playpen", to which all other non-resettable objects have references only through some sort of accessor object...
And then when you need to "reset" you disconnect the existing playpen and make a new one: all the web of objects in the playpen is cast adrift, never to return, and one day to be collected by the GC.
If any of these objects are Closeable
(or not, but have a close
method) you could put them in a Bag
in the playpen as they are created (and possibly opened), and the last act of the accessor before cutting off the playpen would be to go through all the Closeables
closing them... ?
The code would probably look something like this:
accessor.getPlaypen().closeCloseables();
accessor.setPlaypen( new Playpen() );
closeCloseables
would probably be a blocking method, probably involving a latch (e.g. CountdownLatch
), to deal with (and wait as appropriate for) any Runnables
/Callables
in any threads specific to the Playpen
to be ended as appropriate, in particular in the JavaFX thread.
There is no exactly destructor class in Java, class destroyed in java automatically by garbage collector . but you could do that using below one but it's not exact same thing :
finalize()
There was a question that spawned in-depth discussion of finalize , so that you should get more depth if required...
Many great answers here, but there is some additional information about why you should avoid using finalize().
If the JVM exits due to System.exit()
or Runtime.getRuntime().exit()
, finalizers will not be run by default. From Javadoc for Runtime.exit():
The virtual machine's shutdown sequence consists of two phases. In the first phase all registered shutdown hooks, if any, are started in some unspecified order and allowed to run concurrently until they finish. In the second phase all uninvoked finalizers are run if finalization-on-exit has been enabled. Once this is done the virtual machine halts.
You can call System.runFinalization()
but it only makes "a best effort to complete all outstanding finalizations" – not a guarantee.
There is a System.runFinalizersOnExit()
method, but don't use it – it's unsafe, deprecated long ago.
I used to mainly deal with C++ and that is what lead me to the search of a destructor as well. I am using JAVA a lot now. What I did, and it may not be the best case for everyone, but I implemented my own destructor by reseting all the values to either 0 or there default through a function.
Example:
public myDestructor() {
variableA = 0; //INT
variableB = 0.0; //DOUBLE & FLOAT
variableC = "NO NAME ENTERED"; //TEXT & STRING
variableD = false; //BOOL
}
Ideally this won't work for all situations, but where there are global variables it will work as long as you don't have a ton of them.
I know I am not the best Java programmer, but it seems to be working for me.
참고URL : https://stackoverflow.com/questions/171952/is-there-a-destructor-for-java
'Program Tip' 카테고리의 다른 글
모든 Angular 프로젝트에 대해 생성되는 엄청난 수의 파일 (0) | 2020.10.03 |
---|---|
분기 된 저장소에서 풀 요청을 업데이트하는 방법은 무엇입니까? (0) | 2020.10.03 |
Entity Framework의 SqlException-세션에서 실행중인 다른 스레드가 있으므로 새 트랜잭션이 허용되지 않습니다. (0) | 2020.10.03 |
Python에서 현재 사용자 이름을 가져 오는 이식 가능한 방법이 있습니까? (0) | 2020.10.03 |
Bash의 'if'문에서 두 문자열 변수를 어떻게 비교합니까? (0) | 2020.10.03 |