当前位置: 首页 > 知识库问答 >
问题:

如何处理外部库的内存泄漏

靳富
2023-03-14

我有一个小型java应用程序,运行一组计算量大的任务。为了处理这些任务,我使用了一个外部库,它通过本机方法和一些C代码完成大部分计算。不幸的是,在解决一个任务后,库会遭受严重的内存泄漏,因此每次应用程序执行只能解决一个任务。

库中的编码人员知道内存问题,但尚未修复,可能永远也不会修复(这与java垃圾收集器不能正确使用本机inferface有关)。由于这个特定的库没有其他选择,我正在寻找通过顺序执行应用程序来解决任务的选项。

目前,我有一个bash包装器脚本,它获取应该执行的任务的列表,对于每个任务,脚本调用应用程序,只需执行这一个任务。

由于任务通常需要以前任务的结果,这涉及到将执行结果序列化和反序列化到文件。对我来说,这似乎不是一个好的实践,也因为用户基本上没有办法与程序控制流进行交互。

有人知道我如何在一个java应用程序中执行这个连续的任务吗?我想这将涉及为每个任务执行启动一个新的JVM,希望只传输任务结果,而不是将内存泄漏从新JVM传输到我的应用程序

编辑提供更多信息:

>

  • 改变问题的根源:不幸的是,这个库不是开源的,我既不能访问本机方法,也不能访问java接口api。

    新进程/JVM:在这种情况下是一样的吗?我对java进程api或启动新的JVM没有太多经验。我的假设是这将涉及使用ProcessBuilder.start()启动一个具有自己的main函数的单独java程序?

    数据交换:它只有几个KB,因此性能不是问题。尽管如此,没有文件的解决方案会更好,但如果我正确理解内存映射文件也使用本地文件。另一方面,套接字听起来很有希望。

  • 共有2个答案

    严修谨
    2023-03-14

    那要看情况而定。您是否有此外部应用程序的源代码,即是否可以重新编译它?显然,最简单的方法是从根本上修复泄漏。然而,这可能不切实际。如果库(如您所说)是通过本机方法和一些C代码实现的,我认为问题与Java垃圾收集器工作不正常无关。本机方法和C代码通常不会将其数据存储在JVM的堆上,因此不会进行垃圾收集,也就是说,库的工作是在其自身之后进行清理。

    如果泄漏确实存在于库公开的Java代码位中,那么有一种方法。内存泄漏Java通过忘记引用而发生,例如考虑以下示例:

    class Foo {
    
      private ExpensiveObject eo; 
    
      Foo(ExpensiveObject eo) {
        this.eo = eo;
      }
    }
    

    只要引用它的Foo实例,ExpensiveObject(至少)就处于活动状态。如果您(或您的库)没有很好地隔离实例生命周期,您就会陷入麻烦。如果您没有机会重构,那么可以使用反射来清除代码中其他地方的最大混乱:

    void release(Foo foo) {
      Field f = Foo.class.getDeclaredField("eo");
      f.setAccessible(true);
      f.set(foo, null);
    }
    

    然而,这应该被认为是最后的手段,因为它是一个相当黑客。

    或者,一种更好的方法通常是派生另一个JVM实例来完成脏活。看起来你已经在做类似的事情了。通过分叉JVM,可以在进程级别隔离内存的使用。一旦进程死亡,操作系统将释放所有内存。这种方法的问题通常是平台兼容性,但由于您已经使用了本机库,这不会使您的情况恶化。

    您说您目前使用文件在这些不同的进程之间进行通信。为什么需要将数据存储在文件中?如果性能对此事很重要,请考虑使用套接字或内存映射文件(NIO)。

    唐骏祥
    2023-03-14

    有趣的是,我也遇到过同样的问题。根据定义,面对必须使用但无法升级的错误库,您需要接受没有什么是最佳实践或良好做法。

    我们提出的解决方案是在库自身的过程中隔离对库的调用。此进程是主进程的子进程。主进程包含好代码,子进程包含坏代码。然后,我们能够跟踪子进程的调用次数,并在达到一定数量时将其删除。我们知道,我们可以在子进程损坏之前进行X调用。

    由于问题的性质,提出一个新的过程使我们能够在重复之前进行另一个X调用。

    成功调用时,任何状态都返回给主进程。在不成功调用期间收集的任何状态都被丢弃,我们重新开始。

    同样,以上这些都不是“好的”,但对我们有用。

    值得一提的是,如果我再做一次,我会使用Akka和远程演员,这将使所有的子过程、远程处理等变得简单得多。

     类似资料:
    • 本文向大家介绍请你说说C++如何处理内存泄漏?相关面试题,主要包含被问及请你说说C++如何处理内存泄漏?时的应答技巧和注意事项,需要的朋友参考一下 使用varglind,mtrace检测

    • 我尝试导入commons-io-2.6。jar和commons-lang-2.6。将jar(此处可用)转换为处理草图。 我将这些JAR放在位于处理根目录下的libraries文件夹中,但处理无法识别我的导入: 如何在处理过程中导入像Apache这样的外部jar?

    • 本文向大家介绍内存泄漏和内存溢出是什么?一般怎么处理内存泄漏?相关面试题,主要包含被问及内存泄漏和内存溢出是什么?一般怎么处理内存泄漏?时的应答技巧和注意事项,需要的朋友参考一下 (1)内存溢出(OOM)和内存泄露(对象无法被回收)的区别。 (2)引起内存泄露的原因 (3)内存泄露检测工具 ------>LeakCanary 内存溢出 out of memory:是指程序在申请内存时,没有足够的内

    • 我一直在读这方面的文章,原因是Bazel在二进制文件的中只添加了它的直接依赖项。因为是传递依赖项,所以二进制文件找不到它。 为了解决这个问题,我可以想到以下几个黑客: > 添加难看的链接器标志,告诉Bazel添加到而不是。但是,这被认为是一个坏主意,因为不推荐使用,并且不允许通过重写。 使用而不是 使用而不是. 谢了!

    • 在阅读了大量有关MAT的内容后,我使用我的生产堆转储来分析内存泄漏问题。下面是泄漏报告错误: 线程org.apache.tomcat.util.threads.taskthread@0x6d8be0a30 http-bio-8443-exec-115保留总大小为3,695,816,440(89.03%)字节的局部变量。 内存累积在“'<'System class Loader'>”加载的“java

    • 请看看下面的代码: 当我使用这样的处理程序时,我收到一个警告“处理程序应该是静态的,否则它很容易发生内存泄漏。有人能告诉我最好的方法是什么吗?