我正在尝试获得两个矩形的交点。我有一个方法可行,但当我用40000矩形的算法测试它时,我得到一个OutOfMemory错误。我检查交叉点的次数完全是O(n²),但是它花费的时间不是。 我认为内存不足只是因为有太多的对象,但是它花费的时间不是O(n²)(通过加倍测试测试)对我没有意义,我无法弄清楚为什么它正在这样做。
这是我获取交集的代码
public void getIntersections(Rectangle r, Collection<double[]> c) {
x1 = Math.max(this.getLowerLeftX(), r.getLowerLeftX());
y1 = Math.max(this.getLowerLeftY(), r.getLowerLeftY());
x2 = Math.min(this.getUpperRightX(), r.getUpperRightX());
y2 = Math.min(this.getUpperRightY(), r.getUpperRightY());
if(this.contains(x1,y1) && r.contains(x1,y1)) {
inter[0] = x1;
inter[1] = y1;
c.add(inter.clone());
}
if(this.contains(x1,y2) && r.contains(x1,y2)){
inter[0] = x1;
inter[1] = y2;
c.add(inter.clone());
}
if(this.contains(x2,y1) && r.contains(x2,y1)){
inter[0] = x2;
inter[1] = y1;
c.add(inter.clone());
}
if(this.contains(x2,y2) && r.contains(x2,y2)){
inter[0] = x2;
inter[1] = y2;
c.add(inter.clone());
}
}
我试图将此作为内存和CPU高效,但它仍然无法正常工作。 非常感谢任何帮助。
编辑: 调用此函数的算法:
public void execute() {
List<Rectangle> rectangles = this.getRectangles();
Queue<Rectangle> q = new LinkedList<Rectangle>();
q.addAll(rectangles);
System.out.println(q.size());
while(!q.isEmpty()){
Rectangle check_rect = q.poll();
for (Rectangle rect: q) {
check_rect.getIntersections(rect, this.getIntersections());
}
}
}
助手功能:
public boolean contains(double x, double y){
return ((x == this.getLowerLeftX() || x == this.getUpperRightX()) ||
(y == this.getLowerLeftY() || y == this.getUpperRightY())) &&
x >= this.getLowerLeftX() && x <= this.getUpperRightX() &&
y >= this.getLowerLeftY() && y <= this.getUpperRightY();
}
对于我使用的十字路口集合:
this.intersections = new ArrayDeque<>();
outOfMemory Exception总是在尝试放大ArrayDeque&lt;&gt;()时发生,它只存储double [2]中的交叉点。所以40000矩形之间似乎有太多的交叉点。 另一个问题似乎是内存耗尽之前的迭代,它真的变慢了,这是因为交换还是其他内存管理?
答案 0 :(得分:-1)
好的,这是:你的算法或多或少是二次的。如果你在每次运行中进行多次运行的次数与之前的运行次数相同,并且计算后续运行对的持续时间的商数,你会发现它或多或少地落在3.5到4.5之间(丢弃运行的元素很少,你需要几万才能让它足够稳定。)
问题是20K很好,但乘以2得到40K就会有所改变。
更改的是JVM将所有结果保存在其堆中的能力。正如user3707125所说。我用51200个矩形运行你的算法。
堆已满后,垃圾收集器开始疯狂尝试释放一些内存,但没有任何东西可以释放 - 所有对象都可以访问。过了一会儿,你得到一个OutOfMemoryException
,上面写着“超出GC开销限制”的信息。这意味着GC使用了太多时间但回收的内存太少(我认为默认值是CPU时间的98%和堆的2%)。
正如您所看到的,包含坐标的double []对象占据了堆的大部分,然后是Object [] - 这将是ArrayDeque的内部数组。
你能做什么?当你运行应用程序时,你必须增加JVM的堆大小,就像user3707125所说的那样。你通过传递,例如-Xmx8g
标记为VM选项。 8g
这里意味着8千兆字节。
我在成功完成该过程后接受了它。
您可以做的另一件事是考虑如何减少内存占用。也许使用花车而不是双打?您可以为动态数组doubles
编写自定义解决方案(但不是Doubles
!使用此处的基元)并保持平面结构,即不是将每个点都作为两个双精度的单独数组,将它们全部并排放在动态双阵列中(两个点将占用4个槽)。这将消除对一个指针层的需要,每个指针需要8个字节(假设为64位架构)和数组长度(4个字节),这会增加大量内存。尽管如此,无论你如何调整算法的空间使用,增加矩形的数量都会非常快地占用内存。 Meier说40000矩形并不多,但我认为你的测试数据有很多交叉点 - 这意味着你需要存储的数据量是O(n²),而不仅仅是计算它的时间。