假设我有一个类,它做一些繁重的处理,操作几个集合。我想做的是确保这样的操作不会导致内存不足,或者更好的是,我想设置一个阈值,它可以使用多少内存。
class MyClass()
{
public void myMethod()
{
for(int i=0; i<10000000; i++)
{
// Allocate some memory, may be several collections
}
}
}
class MyClassTest
{
@Test
public void myMethod_makeSureMemoryFootprintIsNotBiggerThanMax()
{
new MyClass().myMethod();
// How do I measure amount of memory it may try to allocate?
}
}
做这件事的正确方法是什么?或者这是不可能/不可行的?
8条答案
按热度按时间l3zydbqr1#
我可以想到几个选择:
您也可以编写自己的基准测试来计算内存。
1.只有一个线程在运行。
1.创建一个新的数组来存储要分配的对象。这样在GC运行期间这些对象就不会被收集。
1.一个月一次,一个月一次
1.分配你的对象。把它们放到数组中。
System.gc()
,memoryAfter = runtime.totalMemory() - runtime.freeMemory()
这是我在lightweight micro-benchmark tool中使用的一种技术,它能够以字节精度测量内存分配。
owfi6suc2#
你可以使用profiler(例如JProfiler)来查看类的内存使用情况。或者,正如前面提到的Areo,只是打印内存使用情况:
mwecs4sa3#
要测量当前内存使用情况,请使用用途:
一个月一次,一个月一次
下面是一个很好的例子:get OS-level system information
但是这种测量并不精确,但它可以给予你很多信息。另一个问题是
GC
,它是不可预测的。b1payxdu4#
下面是Netty的一个例子,它做了类似的事情:MemoryAwareThreadPoolExecutor. Guava的cache class也有一个基于大小的回收。你可以看看这些源代码并复制它们的操作。特别是,这里是Netty如何估计对象大小的。本质上,你应该估计你在方法中生成的对象的大小并进行计数。
获取总体内存信息(例如可用/使用了多少堆)将帮助您决定分配给方法的内存使用量,但不能跟踪单个方法调用使用了多少内存。
在大多数情况下,通过限制在给定点可以有多少对象来限制内存使用(例如,通过使用有界队列)已经足够好了,而且实现起来要简单得多。
ie3xauqp5#
这个问题有点棘手,因为Java可以在处理过程中分配大量的短期对象,这些对象随后将在垃圾收集过程中被收集。在公认的答案中,我们不能肯定地说垃圾收集在任何给定的时间都运行过。即使我们引入一个循环结构,使用多个
System.gc()
调用,垃圾收集可能会在我们的方法调用之间运行。更好的方法是使用https://cruftex.net/2017/03/28/The-6-Memory-Metrics-You-Should-Track-in-Your-Java-Benchmarks.html中建议的一些变体,其中
System.gc()
被触发,但我们也等待报告的GC计数增加:这仍然只给出了代码在给定时间实际分配的内存的近似值,但该值通常更接近人们通常感兴趣的值。
xeufq47z6#
下面是一个在单独的线程中运行内存使用的示例代码。由于GC可以在进程运行时随时触发,因此它将记录每秒的内存使用情况并报告最大内存使用量。
runnable
是需要测量的实际进程,runTimeSecs
是该进程将运行的预期时间。这是为了确保线程计算内存不会在实际进程之前终止。czq61nw17#
估计内存使用量最简单的方法是使用
Runtime
类中的方法。我建议不要依赖它,而只是将其用于近似估计。理想情况下,您应该只记录这些信息并自行分析,而不是将其用于测试或代码的自动化。
也许它不是很可靠,但是在封闭的环境中,比如单元测试,它可能会给予你接近现实的估计。
特别是不能保证在调用
System.gc()
垃圾收集器后会在我们期望的时候运行(这只是对GC的建议),这里描述的freeMemory
方法有精度限制:https://stackoverflow.com/a/17376879/1673775,可能还有更多的警告。溶液:
2w2cym1i8#
许多其他的答案都警告说GC是不可预测的。然而,从Java 11开始,Epsilon garbage collector已经包含在JVM中,它不执行GC。
指定以下命令行选项以启用它:
这样就可以确保垃圾回收不会干扰内存计算。