Java 获取非O(n²;)和OutOfMemory矩形的交点

Java 获取非O(n²;)和OutOfMemory矩形的交点,java,geometry,Java,Geometry,我想得到两个矩形的交点。我有一个有效的方法,但是当我用40000个矩形的算法测试它时,我得到了一个OutOfMemory错误。我检查交叉口的次数完全是O(n²),但所花的时间却不是。 我认为内存不足只是因为对象太多,但它所花费的时间不是O(n²)(通过加倍测试测试)对我来说没有意义,我也不明白它为什么会这样做 这是我到达十字路口的代码 public void getIntersections(Rectangle r, Collection<double[]> c) { x

我想得到两个矩形的交点。我有一个有效的方法,但是当我用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());
    }
}
public void getcrossions(矩形r,集合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(此包含(x1,y1)和&r.包含(x1,y1)){
inter[0]=x1;
inter[1]=y1;
c、 添加(inter.clone());
}
if(本包含(x1,y2)和&r包含(x1,y2)){
inter[0]=x1;
inter[1]=y2;
c、 添加(inter.clone());
}
如果(此包含(x2,y1)和&r包含(x2,y1)){
inter[0]=x2;
inter[1]=y1;
c、 添加(inter.clone());
}
if(本包含(x2,y2)和r包含(x2,y2)){
inter[0]=x2;
inter[1]=y2;
c、 添加(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 void execute(){
List rectangles=this.getRectangles();
队列q=新的LinkedList();
q、 addAll(矩形);
System.out.println(q.size());
而(!q.isEmpty()){
矩形检查_rect=q.poll();
对于(矩形矩形:q){
检查_rect.getcrossions(rect,this.getcrossions());
}
}
}
助手功能:

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();
}
公共布尔包含(双x,双y){
返回((x==this.getLowerLeftX()| | x==this.getUpperRightX())||
(y==this.getLowerLeftY()| | y==this.getUpperRightY())&&

x>=this.getLowerLeftX()&&x=this.getLowerLeftY()&&y好的,这里是:你的算法或多或少是二次的。如果你进行多次运行,每次运行的元素数量是前一次运行的两倍,并计算后续运行对的持续时间的商,你会发现它或多或少在3.5和4.5之间(放弃元素很少的运行,需要数千个元素才能使其足够稳定)

问题是20K很好,但是乘以2得到40K会改变一些东西

改变的是JVM在其堆中保存所有结果的能力。正如user3707125所说,我已经用51200个矩形运行了您的算法

您可以在此处查看结果:

堆满后,垃圾收集器疯狂地试图释放一些内存,但没有什么可以释放的-所有对象都是可访问的。过了一段时间,您会得到一个
OutOfMemoryException
,消息为“超出GC开销限制”。这意味着GC使用了太多时间,但回收的内存太少(我认为默认值是98%的CPU时间和2%的堆)

您可以在此处看到堆的结构:

如您所见,包含坐标的double[]对象占据了堆的大部分,其次是Object[]——这将是ArrayDeque的内部数组

你能做什么?你必须在运行应用程序时增加JVM的堆大小,就像用户3707125所说的那样。你可以通过将例如
-Xmx8g
标志作为VM选项来实现这一点。
8g
这里指的是8g字节

您可以在此处看到使用该选项的跑步:

我在过程成功完成后服用了它


您可以做的另一件事是考虑如何减少内存占用。可能使用浮点而不是双精度?您可以为
双精度
(但不是
双精度
)的动态数组编写自定义解决方案。请在此处使用原语)并保持平面结构,即不是将每个点作为两个双精度的单独数组,而是将它们并排放在动态双精度数组中(两个点将占用4个插槽)。这样就不需要一层指针,每个指针占用8个字节(假设64位体系结构)和数组长度(4个字节),这会增加很多内存。但是,无论您如何调整算法的空间使用,增加矩形的数量都会很快消耗内存。Meier说40000个矩形并不多,但我假设您的测试数据有很多交叉点-这意味着您需要存储的数据量是O(n²),而不仅仅是计算它所需的时间。

您有没有研究过性能下降的动力学(1000、5000、10000个矩形)?此外,您还应提供调用此方法的代码,因为可能存在问题。此外,您的方法会产生副作用,这被认为是不好的做法。通常,您希望返回新的交叉点对象,而不是操作输入和全局变量。您能提供此处使用的所有方法的实现吗?这意味着所有
getLowerRight
getUpperLeft
等。方法和
包含
方法。此外,请包括
inter
数组的声明。我添加了更多信息,以便您可以看到我在做什么。由于您没有回答我的评论,我会澄清。我的假设是您没有足够的内存来计算答案,因此,请尝试调用1k、5k、10k矩形的代码,然后在调用结束时查看内存消耗:
Runtime.getRuntime().freemory()
。如果矩形数量变小,接近程序停止工作的边界-
this.intersections = new ArrayDeque<>();