我一直在阅读关于finalize()的很多新手Java问题,并发现有点令人困惑的是,没有人真正说明finalize()是一种不可靠的清理资源的方法.我看到有人评论说他们用它来清理Connections,这真的很可怕,因为接近Connection的关闭的唯一方法就是最终实现try(catch).
我没有受过CS的教育,但是我已经用Java专业编程近十年了,我从未见过有人在生产系统中实现finalize().这仍然不意味着它没有它的用途,或者我与之合作过的人一直在做正确的事.
所以我的问题是,实现finalize()的用例是什么,无法通过语言中的其他进程或语法更可靠地处理?
请提供具体的方案或您的经验,只是重复Java教科书,或最终确定的用途是不够的,这不是这个问题的意图.
我不是问这个问题,因为垃圾收集的优点首先.我提出这个问题的主要原因是我知道Bjarne Stroustrup已经说过C++在某些时候会有一个垃圾收集器.
话虽如此,为什么还没有添加?已经有一些垃圾收集器用于C++.这只是那些"说起来容易做起来难"的事情吗?还是有其他原因没有添加(并且不会在C++ 11中添加)?
交叉链接:
为了澄清,我理解为什么C++在第一次创建时没有垃圾收集器的原因.我想知道为什么收藏家不能加入.
null在Java中分配未使用的对象引用是否以任何可测量的方式改进了垃圾收集过程?
我用Java语言(C#)的经验告诉我,经常是反直觉的,试图智取虚拟机或JIT编译器,但我已经看到同事用这个方法,我很好奇,如果这是一个很好的做法挑向上或那些巫术迷信编程的一个?
执行后我很难理解m1 = null; m2 = null;.有多少个对象可以进行垃圾回收?
public class MyTest {
MyTest m;
void show() {
System.out.println("Hello this is show method.");
}
public static void main(String args[]) {
MyTest m1 = new MyTest();
MyTest m2 = new MyTest();
MyTest m3 = new MyTest();
m1.m = m2;
m2.m = m3;
m3.m = m1;
m1 = null;
m2 = null;
// Question here: How many objects will be eligible for garbage collection?
}
}
Run Code Online (Sandbox Code Playgroud) 我一直在研究我的代码中的一个错误,这个错误似乎是由一些"丑陋的"终结器代码引起的.代码看起来大致如此
public class A {
public B b = new B();
@Override public void finalize() {
b.close();
}
}
public class B {
public void close() { /* do clean up our resources. */ }
public void doSomething() { /* do something that requires us not to be closed */ }
}
void main() {
A a = new A();
B b = a.b;
for(/*lots of time*/) {
b.doSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
我认为正在发生的事情是,a在第二行之后检测到没有引用main()并获得GC并最终确定终结器线程 - 当for循环仍然发生时,使用 …
提供以下代码:
class A {
Boolean b;
A easyMethod(A a){
a = null;
return a;
}
public static void main(String [] args){
A a1 = new A();
A a2 = new A();
A a3 = new A();
a3 = a1.easyMethod(a2);
a1 = null;
// Some other code
}
}
Run Code Online (Sandbox Code Playgroud)
问题是之前有多少对象符合垃圾收集的条件// Some other code.
然后正确答案是(至少那是面试官的答案):2 - 布尔值,b因为它是一个包装器和a1.
你能帮我解释一下为什么a2而a3不是垃圾收集?
后期编辑:
谢谢你的回答,我会在那之后发一些面试反馈:).
在Java中,我做了类似下面的事情而没有考虑太多:
public class Main {
public void run() {
// ...
}
public static void main(String[] args) {
new Main().run();
}
}
Run Code Online (Sandbox Code Playgroud)
然而,最近我不确定这样做是否安全.毕竟,在Main创建对象之后没有对该对象的this引用(好吧,有引用,但这会计数吗?),所以看起来垃圾收集器可能会在执行过程中删除对象的危险一些东西.所以也许这个main方法应该是这样的:
public static void main(String[] args) {
Main m = new Main();
m.run();
}
Run Code Online (Sandbox Code Playgroud)
现在,我敢肯定的是,第一个版本的作品,我从来没有任何问题,但我想知道,如果它是安全的.所有的情况下做的(不仅是在一个特定的JVM,但最好根据语言规范对此类案例的说法).
今天我正在Closeablekotlin中实现一个,就像我过去在java中所做的那样,我希望finalize()在客户端代码忘记关闭它的情况下实现一个最后的回退,使得关键资源无法回收.尽管这种回退不可靠,但我认为这种资源至关重要,足以增加这种后备.但是,kotlin.Any没有声明一个finalize方法,这意味着我不能简单地这样做:
class Resource: Closeable {
fun close() {}
override fun finalize() { close()}
}
Run Code Online (Sandbox Code Playgroud)
这不好,至少没有它应该的那么好.现在我恢复普通Java作为解决方法.有谁知道如何在纯Kotlin中做到这一点?
PS:我目前的解决方法:
FinalizedCloseable.java:
public abstract class FinalizedCloseable implement Closeable {
@Override protected void finalize() { close(); }
}
Run Code Online (Sandbox Code Playgroud)
科特林:
class Resource: FinalizedCloseable(), Closeable {
fun close() {}
override fun finalize() { close()}
}
Run Code Online (Sandbox Code Playgroud)
但是这种解决方法需要一个超类.如果下次我的其他人Resource已经有了一个超类,那么如果没有很多样板,这种解决方法将无法工作.
编辑:现在我知道如何实现finalize(),但IDEA kotlin插件不够聪明,不知道这是一个终结器,因此用一些警告标记它.经过一段时间的努力,我发现如何压制这些警告,我想分享它:
class C {
@Suppress("ProtectedInFinal", "Unused") protected fun finalize() {}
}
Run Code Online (Sandbox Code Playgroud) 这主要是出于好奇.
如果有人遇到Object.finalize()的任何良好用法,除了调试/记录/分析目的外,我还在徘徊?
如果你没有遇到任何你会说好的用法会是什么?
UPD 21.11.2017:该错误已在JDK中修复,请参阅Vicente Romero的评论
摘要:
如果for语句用于任何Iterable实现,则集合将保留在堆内存中直到当前作用域(方法,语句体)的结尾,并且即使您没有对集合和应用程序的任何其他引用也不会进行垃圾回收需要分配一个新的内存.
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8175883
https://bugs.openjdk.java.net/browse/JDK-8175883
例子:
如果我有下一个代码,它会分配一个包含随机内容的大字符串列表:
import java.util.ArrayList;
public class IteratorAndGc {
// number of strings and the size of every string
static final int N = 7500;
public static void main(String[] args) {
System.gc();
gcInMethod();
System.gc();
showMemoryUsage("GC after the method body");
ArrayList<String> strings2 = generateLargeStringsArray(N);
showMemoryUsage("Third allocation outside the method is always successful");
}
// main testable method
public static void gcInMethod() {
showMemoryUsage("Before first memory allocating");
ArrayList<String> strings …Run Code Online (Sandbox Code Playgroud)