(1)我有一个资源密集型函数f,它的调用会导致大量的内存分配。因为在f内部,将会有大量的对象关系集合被构建到内存中。
(2)然而,在我的工作负载中,我碰巧需要迭代地调用函数f,比如在for循环中,以及超过1K次的map函数。通过这种方式,调用f的循环很快就会破坏JVM。
for {
calling f here
}为了让上面的工作负载正常工作,我在调用f之前使用Thread.sleep引入间隔来延迟f调用的每次迭代,如下所示
for {
Thread.sleep (10)
calling f here
}这种运行时间确实减少了总内存使用量,从而使大量工作负载能够正常工作。
(3)然而,有一些已知的影响:(a)增加GC的频率和(b)增加总响应时间。因此,我需要调整客户端和服务器的超时配置。(c)延迟可以是线性增长的,这意味着当迭代需要增长时,不会扩大规模。(d)如果同时存在触发上述相同工作负载的并发请求,则其他请求将超时。
我的问题:如何从字面上调用资源密集型函数:
(A)对于(2)在合理的响应时间内同时处理上述一个大型工作负载的最佳方法是什么?(B) (2)同时处理多个并发大型工作负载的最佳方法是什么?
发布于 2019-07-22 14:27:27
如果f没有泄漏资源,那么在单个线程中调用它1000次就不会崩溃,因为在任何给定的时间,它只为一个调用分配资源。
所以我猜你要么有一个内存泄漏,要么你从太多不同的线程调用它。既然Thread.sleep帮了我的忙,我赌的是第二个。但这并不是一个可靠的解决方案。
要限制对f的并发调用数量,您可以在专用ExecutionContext上运行它。
val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10))
..
..
Future {
call f
}(ec)其中,在f的所有调用方之间共享ec实例。
increase the frequency of GC问题通常无法解决:无论您如何安排执行,都必须收集您生成的所有垃圾。但是,如果程序必须是低延迟的,那么稍微调整一下GC设置是有意义的。如果有许多线程产生大量短命垃圾,那么你需要更多的空间来存放新的垃圾,而需要更少的空间来存放长寿的垃圾。它曾经是XX:NewSize设置,但也许现代垃圾收集器的工作方式有所不同。
https://stackoverflow.com/questions/57138058
复制相似问题