提问人:Bolpat 提问时间:11/11/2023 最后编辑:Bolpat 更新时间:11/13/2023 访问量:55
如何关闭AutoClosable类型的静态变量?
How to close a static variable of AutoClosable type?
问:
我是一个 Java 库的作者,该库提供对我们公司销售的 C++ 库的 Java 访问。其中一个类的实例在以下意义上“拥有”C++ 对象:该类具有一些私有字段,这些字段由某些方法设置,并具有指向 C++ 堆的(唯一)指针的角色。由于 C++ 堆不是垃圾回收的,因此当拥有 Java 对象不再需要内存时,必须手动释放内存,尤其是当不再需要拥有 Java 对象本身时,因此该类实现并释放实例拥有的所有 C++ 内存。理想情况下,用户将在该类的实例上使用 -with-resources。long
native
AutoClosable
close()
try
一位客户抱怨说,SonarQube 警告他们没有被调用来释放资源,并建议在对象上使用 -with-resources,但该对象由变量或等效物持有,并且一直存在到应用程序关闭(据我所知)。我想帮助他们,但删除(正如他们建议的那样)根本不正确。问题不在于内存:当应用程序结束并卸载 C++ 库时,内存资源无论如何都会被释放(由操作系统释放)。close()
try
static
AutoClosable
那么,如何关闭静态变量所持有的对象,最好是以 SonarQube 检测的方式呢?Java 似乎没有可以使用的类初始值设定项的对立面。AutoClosable
我无法访问 SonarQube 来玩一玩,看看什么可以工作,即当 SonarQube 识别出将被调用时。我将告诉他们,他们应该适当地重新配置 SonarQube 或禁止显示警告。问这个问题,我想确保它本质上是最好的行动方案。 如果这是真的,“是的,是的”将是一个合适的答案。当然,不使用全局状态,即没有全局状态是不费吹灰之力的,但我想他们已经知道了。close()
static
AutoClosable
似乎没有人遇到对象的问题,因为在 Stack Overflow 上没有关于它的问题。
我认为这类似于 .NET (C#),我发现这个问题非常多,但是答案特定于用例和 .NET,也没有提供通用解决方案。static
AutoClosable
AutoClosable
IDisposable
答:
一位客户抱怨说,SonarQube 警告他们 close() 不是为了释放资源而调用的,并建议在对象上使用 try-with-resources,但该对象由静态变量或等效物保存,并一直存在到应用程序关闭(据我所知)。
“医生,我把锤子砸到脸上很痛!”
那就别再这样做了。
SonarQube 是一个工具。它可以配置为只说傻话,类似于那把锤子。解决方法不是尝试长出防锤面。解决方法是简单地停止做唯一目的是伤害的事情。
不幸的是,您的客户可能不愿意听到这一点。
但如果是这样,他们可以告诉声纳库贝停止这样做。他们甚至可以添加一个简单的评论,告诉 sonarqube 不要抱怨那个特定的情况。
似乎没有人遇到静态 AutoClosable 对象的问题,因为在 Stack Overflow 上没有关于它的问题。
想要它是一件奇怪的事情,即使是你的客户。如果有一个全局变量具有这种状态,这意味着你的客户的代码是不可测试的(例如,他们不能真正用虚拟实现来替换它)——但是,同样,考虑到它是客户,他们可能不愿意听到这一点。
通常,在应用启动后不久创建一次资源,并将其交给 try-with 块中的其余代码,除非应用退出,否则该块永远不会退出:
public static void main(String[] args) {
try (var out = new FileOutputStream(args[0])) {
yourActualApp(out);
}
类似于上面的东西。这同样适用于您的图书馆。但是,您的客户必须希望摆脱静态的全局字段,并将资源传递到任何地方才能实现此工作,而他们可能不想这样做。
一个可能的解决方案
将代表资源的任何 java 类拆分为 twain。2 个类,这两个类都只是围绕实际实现。一个实现 AutoClosable,另一个不实现。将不“GlobalFoo”的名称命名为“GlobalFoo”,其中 Foo 是您当前的名称 - 并在其 javadoc 中输入此类内容的目的是它在 JVM 的生命周期中存在。这样一来,你的用户必须明确地选择“nono this one lives forever, no need to close it!”,你可以添加一些智能,比如 - 如果它是一个具有唯一键的资源(比如说,它代表一个文件。 文件具有唯一键: 完全限定的文件名! - 您可以存储这些唯一键,如果库的用户尝试使用相同的键创建这样的全局对象,则抛出错误键不止一次。
您可以让一个扩展另一个 - 该扩展器只是添加 AutoClosable,仅此而已。
评论
一位客户抱怨说,SonarQube 警告他们 close() 不是为了释放资源而调用的,并建议在对象上使用 try-with-resources,但该对象由静态变量或等效物保存,并一直存在到应用程序关闭(据我所知)。
如果 SonarQube 是可信的,则用户正在创建类的实例,该实例不受 try-with-resources 语句管理,并且他们没有显式管理。然后有两种可能性:close()
- 对于特定类的实例来说,这是可以的,或者
- 这是一个使用错误。
无论哪种方式,从根本上说,这都是一个“他们”的问题,而不是“你”的问题。
我想帮助他们,但删除 AutoClosable(正如他们建议的那样)根本不正确。
我希望删除(以及您显式实现的任何子接口)将使 SonarQube 静音,因为它将不再将对象识别为其方法相关的对象。我倾向于相信你,那是不正确的。当然,这将使该类无法与 try-with-resources 语句一起使用。这不会使 SonarQube 目前报告的用法比现在更正确或更不正确。AutoClosable
close()
问题不在于内存:当应用程序结束并卸载 C++ 库时,内存资源无论如何都会被释放(由操作系统释放)。
这往往支持一个前提,即上面的 (1) 适用于您的类。但是,未关闭对象还存在其他潜在问题。例如,如果类的实例管理可修改的文件,则无法关闭它们可能意味着如果 VM 异常终止,则某些写入将丢失。但同样,这似乎是一个使用问题,而不是设计或实现问题。
那么,如何关闭静态变量所持有的对象,最好是以 SonarQube 检测的方式呢?Java 似乎没有可以使用的类初始值设定项的对立面。
AutoClosable
通过显式调用它们的方法。 在这里无关紧要,除非它声明了该方法。除了与try-with-finally语句的相关性之外,它没有任何特殊的语义。
你是对的,Java 没有任何类型的钩子用于在清理类之前执行代码,也不能保证未使用的类会被清理,甚至在程序终止时也不会。close()
AutoCloseable
关于这个问题的评论提到了关机钩子,但这些都是糟糕的juju。此外,我怀疑你在类本身中对它们所做的任何事情都会满足 SonarQube,如果你的用户能够成功地使用它们来满足 SonarQube,我会有点惊讶。即使他们这样做了,这真的会让他们的应用程序以更好或更可靠的方式工作吗?
总的来说,我认为首先将对象存储在字段中通常是一个错误。在某种程度上,有一个合理的预期需要关闭,这很难与字段的典型无限可用性相协调。AutoCloseable
static
AutoClosable
static
我将告诉他们,他们应该适当地重新配置 SonarQube 或禁止显示警告。
如果你对对象不关闭(完全)是可以的感到满意,那么这正是我会做的。
当然,不使用全局状态,即没有静态 AutoClosable 是不费吹灰之力的,但我想他们已经知道了。
我不会假设他们确实知道这一点,但我也不会假设他们会在被告知他们不应该做他们正在做的事情时做出良好的反应。从用户支持的角度来看,这也不是特别好的外观。
评论
AutoCloseable
,并且不会调用您在 try-with 块中打开的任何内容。故意。因为没有必要,而且尝试实际上是一个坏主意。
kill
-9
System.exit(0)
close()