Effective Java Item7-不使用Finalizers

Effective Java 2nd Edition Reading Notes

Item7: Avoid Finalizers

不使用Finalizers

 

Finalizers是不可预知的,有时是危险的,并且是不必要的。

C++中,析构函数用于回收资源,而在Java中,通过GC来回收资源。析构函数还用于回收非内存资源,在Java中,通过try{}finally{}来完成同样的工作。

 

首先finalizers并不能保证被马上执行。在对象不可用开始到finalize方法执行之间的时间是任意的。这意味着不能在finalizers中进行具有时间要求的操作。例如在finalizer中关闭文件。[操作系统中可以打开的文件数是有限制的,一旦超过限制,将不能再打开文件。]

何时执行finalizersGC的功能,因JVM的实现不同而不同。使用finalizers在极端的情况下会导致实例回收的延迟,从而发生OutOfMemoryError。规范没有定义finalizers什么时候执行,甚至不能确保finalizers是否会被执行。

永远不要依赖finalizers去实现持久性的更新。例如在finalizers中释放持久性的锁。

 

不要使用System.gc或者System.runFinalization,它们导致finalizers的运行怪异,并且不提供任何保障。

另外,如果未捕获的异常发生在finalizers中,那么异常被忽略(不输出任何信息)finalizer将终止。

同时,使用finalizers会带来严重的性能影响。

Oh, and one more thing:  there is a  severe performance penalty for using finalizers. On my machine, the time to create and destroy a simple object is about 5.6 ns. Adding a finalizer increases the time to 2,400 ns. In other words, it is about 430 times slower to create and destroy objects with finalizers.

 

进行finalize的一个好的办法是提供一个显式的终止方法,同时记录实例的状态,例如提供一个成员变量来记录,在使用其他方法的时候,检查该成员变量的值。如果实例已经被终止,那么抛出IllegalStateException。比较典型的是java.sql.Connection, java.io.InputStream, java.io.OutputStream, java.util.Timer等等。

显式的终止方法通常和try{}finally{}结合使用,在finally中调用终止方法来终止对象。

 

finalizer的实际作用:

Finalizer的一个作用是提供一个Safety net,即万一客户端,例如使用InputStream的其他类忘记关闭流,那么通过finalize方法来关闭,但是最好应该在finalize方法中提供日志输出,提示客户端错误。

例如FileOutputStreamfinalize方法如下:

/**

     * Cleans up the connection to the file, and ensures that the

     * <code>close</code> method of this file output stream is

     * called when there are no more references to this stream.

     *

     * @exception  IOException  if an I/O error occurs.

     * @see        java.io.FileInputStream#close()

     */

    protected void finalize() throws IOException {

       if (fd != null) {

           if (fd == fd.out || fd == fd.err) {

              flush();

           } else {

              close();

           }

       }

    }

Finalizer的另一个作用适用于本地对等对象(java对象通过本地对等对象获取),由于native peer不是java实例,所以GC不会回收对等对象。此时提供finalizer来回收该对象。

<think>好的,我现在需要解决用户的问题:在Kubernetes中,手动删除cattle-system命名空间的finalizers后仍然无法删除,该怎么办。首先,我得回忆一下Kubernetes中finalizers的作用。Finalizers用于确保在资源删除之前执行某些清理操作,比如依赖资源的释放。如果资源卡在终止状态,通常是因为某个finalizer没有被正确处理。 用户已经尝试手动删除finalizers但未成功,可能的情况有哪些呢?可能他们编辑了命名空间的YAML文件,移除了finalizers字段,然后应用了更改,但命名空间仍然存在。这时候需要考虑其他原因,比如APIService或自定义资源的问题,或者控制器的问题。 接下来,我需要逐步分析可能的原因和解决方法。首先,检查APIService是否正常。Cattle-system通常是Rancher使用的命名空间,可能依赖于某些CRD和APIService。如果这些APIService可用,可能导致删除卡住。用户应该检查kube-apiserver的日志,看看是否有相关错误。 然后,确认是否有残留的CRD资源。即使命名空间被标记为删除,如果其中还有未清理的自定义资源,尤其是那些带有finalizers的,可能会导致问题。需要检查这些资源,并尝试删除它们的finalizers。 另外,强制删除命名空间也是一种方法,但需谨慎。可以通过kubectl proxy和curl直接调用API进行删除,但需要获取当前的资源版本,避免冲突。 还有一种可能是控制器的问题,比如Rancher的控制器没有正确响应删除操作。如果Rancher本身已经卸载,但残留的控制器仍在运行,可能会导致问题。此时可能需要检查相关的Pod和控制器是否仍在运行,并确保它们被正确清理。 用户可能遇到的具体步骤包括使用kubectl edit移除finalizers,但操作后未生效,所以需要更深入的排查。比如,检查命名空间的详细状态,是否有错误信息,或者使用kubectl get namespace cattle-system -o yaml查看状态详情。 此外,检查etcd中的数据是否异常。如果有权限,可以直接使用etcdctl删除命名空间条目,但这是高风险操作,需谨慎执行,并确保备份数据。 总结起来,解决步骤可能包括:检查APIService和CRD,删除相关资源,强制通过API删除命名空间,清理etcd数据(最后手段)。同时,用户需要注意操作风险,尤其是在生产环境中,建议备份并逐步验证每一步的影响。</think>在 Kubernetes 中,当命名空间(Namespace)因 `finalizers` 导致无法删除时,通常是因为某些控制器或资源未正确清理。以下是针对 `cattle-system` 命名空间删除问题的分步解决方案: --- ### **1. 确认问题原因** 首先检查命名空间的状态和事件: ```bash kubectl get namespace cattle-system -o yaml kubectl describe namespace cattle-system ``` - 如果输出中显示 `Terminating` 状态且卡住,通常是 `finalizers` 未被释放导致。 --- ### **2. 直接移除 Finalizers(常规方法)** 通过编辑命名空间定义手动移除 `finalizers` 字段: ```bash kubectl get namespace cattle-o json > cattle-system.json ``` - 用编辑器打开 `cattle-system.json`,删除 `spec.finalizers` 字段内容,保存后执行: ```bash kubectl replace --raw "/api/v1/namespaces/cattle-system/finalize" -f ./cattle-system.json ``` --- ### **3. 检查依赖资源** 如果仍然无法删除,可能是命名空间内存在未清理的资源(如 CRD、APIService): #### **3.1 检查并删除 APIService** ```bash kubectl get apiservice | grep cattle- 删除相关的 APIService(如果有): ```bash kubectl delete apiservice <name> ``` #### **3.2 清理残留的 CRD 资源** ```bash kubectl get crd | grep cattle.io # Rancher 相关 CRD 通常带有此标签 ``` - 删除所有关联的 CRD(谨慎操作): ```bash kubectl delete crd <crd-name> ``` -- ### **4. 强制删除命名空间(高风险)** 如果以上方法无效,可通过 Kubernetes API 强制删除: ```bash NAMESPACE=cattle-system kubectl proxy & # 启动代理到本地端口 curl -X PUT http://localhost:8001/api/v1/namespaces/$NAMESPACE/finalize \ -H "Content-Type: application/json" \ --data-binary @- <<EOF { "kind": "Namespace", "apiVersion": "v1", "metadata": { "name": "$NAMESPACE" }, "spec": { "finalizers": [] } } EOF ``` - 确保从 `kubectl get namespace cattle-system -o yaml` 中复制最新的 `resourceVersion` 到请求体中。 --- ### **5. 检查 Etcd 数据(终极手段)** 如果仍失败,可能是 Etcd 中残留数据导致,需直接操作 Etcd: ```bash etcdctl del /registry/namespaces/cattle-system ``` - **注意**:需有 Etcd 访问权限,操作前务必备份数据。 --- ### **6. 验证 Rancher 组件是否卸载** 如果 `cattle-system` 是 Rancher 的命名空间,请确认 Rancher 已正确卸载: ```bash helm list -n cattle-system # 检查是否有残留的 Helm Release kubectl get helmchartconfig -A # 检查 Rancher 相关配置 ``` - 参考 Rancher 官方文档执行完整卸载流程。 --- ### **注意事项** - **生产环境谨慎操作**:直接操作 Etcd 或强制删除可能导致集群稳定。 - **备份数据**:操作前备份 Etcd 和关键资源。 - **依赖组件**:确保相关控制器(如 Rancher)已停止,避免删除后重新创建资源。 如果问题仍未解决,请提供更详细的错误日志(如 `kube-apiserver` 日志),以便进一步诊断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值