-
Type:
Bug
-
Resolution: Duplicate
-
Priority:
P3
-
Affects Version/s: 5.0
-
Component/s: client-libs
-
x86
-
windows_xp
FULL PRODUCT VERSION :
java version "1.5.0_05"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
The methods Area.add() and Area.subtract() sometimes causes an
OutOfMemoryError. This can happen when the Shape used to create
the area was created using the PathIterator.SEG_QUADTO constant.
Although this doesn't happen very often, it can be reliably
reproduced. In five minutes of running our test data, we drew 200
graphs, which made use of 247398 additions and 247399 subtractions of
areas made from 533510 SET_QUADTO curves, and encountered this bug
four times, twice with adding and twice with subtracting. Since this
makes it nearly certain that our customers will see the bug, we need
a fix, in spite of its seemingly rare nature. (Don't think of this as
four errors in 247,000 cases, think of it as 4 errors in 200 cases.)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Build and run the test case provided.
The program will load two shapes and create Areas. It will print out
the parameters to the GeneralPath methods it calls to make those
shapes. Then it will print out "Attempting to add..." then it
will try to subtract one area from the other.
It then will repeat this process with two new areas and attempt to subtract them.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The add and subtract should succeed, and the program should exit cleanly after
printing out "Addition succeeded" and "Subtraction succeeded." It shouldn't
take more than a second.
ACTUAL -
The program hangs for ten seconds or so, then prints out
"java.lang.OutOfMemoryError: Java heap space" for both the addition and the
subtraction.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.OutOfMemoryError: Java heap space
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.PathIterator;
import java.awt.geom.GeneralPath;
import java.io.*;
public class AreaSubtractBug {
public static final String SEG_CLOSE = " SEG_CLOSE";
public static final String SEG_CUBICTO = " SEG_CUBICTO";
public static final String SEG_LINETO = " SEG_LINETO";
public static final String SEG_MOVETO = " SEG_MOVETO";
public static final String SEG_QUADTO = " SEG_QUADTO";
public static final byte[] strokedLineToSubtract = {
0, 11, 32, 83, 69, 71, 95, 77, 79, 86, 69, 84, 79, 68, 117, 7, -63, 67, 15, 6,
87, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, 31, 16, 67, 15,
23, 5, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 117, 68, -12, 67,
15, 50, 54, 68, 117, 103, 16, 67, 15, 50, 59, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 117, 110, 14, 67, 15, 50, 59, 0, 11, 32, 83, 69, 71, 95, 81,
85, 65, 68, 84, 79, 68, 117, -56, 26, 67, 15, 48, -15, 68, 118, 22, 75, 67, 14, 112,
95, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 118, 61, 115, 67, 14,
15, 10, 68, 118, 94, 93, 67, 13, 127, -74, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78,
69, 84, 79, 68, 118, 103, -80, 67, 13, 87, 15, 0, 11, 32, 83, 69, 71, 95, 81, 85,
65, 68, 84, 79, 68, 118, 21, -76, 67, 14, -81, -105, 68, 117, -100, -84, 67, 14, -72, 72,
0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, -88, 84, 67, 14, -72,
72, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 117, 108, 85, 67, 14,
-73, 106, 68, 117, 53, 117, 67, 14, 74, -61, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78,
69, 84, 79, 68, 117, 72, 27, 67, 14, 112, 14, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 118, 87, -51, 67, 5, -16, 100, 0, 11, 32, 83, 69, 71, 95, 76,
73, 78, 69, 84, 79, 68, 118, 69, 39, 67, 5, -53, 25, 0, 11, 32, 83, 69, 71, 95,
81, 85, 65, 68, 84, 79, 68, 117, -5, -93, 67, 5, 57, 38, 68, 117, -88, 84, 67, 5,
56, 72, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, -100, -84, 67,
5, 56, 72, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 117, 12, 86,
67, 5, 64, -7, 68, 116, -89, -76, 67, 6, -22, -51, 0, 11, 32, 83, 69, 71, 95, 76,
73, 78, 69, 84, 79, 68, 116, -98, 97, 67, 7, 19, 116, 0, 11, 32, 83, 69, 71, 95,
81, 85, 65, 68, 84, 79, 68, 116, -75, -100, 67, 6, -83, -7, 68, 116, -44, -9, 67, 6,
95, -59, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 117, 26, -119, 67,
5, -76, 14, 68, 117, 110, 14, 67, 5, -78, 59, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 117, 103, 16, 67, 5, -78, 59, 0, 11, 32, 83, 69, 71, 95, 81,
85, 65, 68, 84, 79, 68, 117, 122, -71, 67, 5, -78, 22, 68, 117, -119, -60, 67, 5, -68,
-61, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, 114, 117, 67, 5,
-84, 21, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, 7, -63, 67,
15, 6, 87, 0, 10, 32, 83, 69, 71, 95, 67, 76, 79, 83, 69,};
public static final byte[] negSpace = {
0, 11, 32, 83, 69, 71, 95, 77, 79, 86, 69, 84, 79, 68, 116, -33, -12, 67, 4, 30,
-23, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 118, 59, 73, 67, 6,
-43, -109, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, 100, -97, 67,
13, -118, -32, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 116, 9, 75,
67, 10, -44, 54, 0, 10, 32, 83, 69, 71, 95, 67, 76, 79, 83, 69,};
public static final byte[] strokedLineToAdd = {
0, 11, 32, 83, 69, 71, 95, 77, 79, 86, 69, 84, 79, 68, 98, -100, -76, 67, -85, -36,
6, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, -76, 4, 67, -85,
-48, 21, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 98, -102, -29, 67,
-85, -36, -5, 68, 98, -112, 107, 67, -85, -35, 5, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 98, -84, 99, 67, -85, -35, 5, 0, 11, 32, 83, 69, 71, 95, 81,
85, 65, 68, 84, 79, 68, 98, -87, 1, 67, -85, -35, 1, 68, 98, -107, -10, 67, -85, -43,
23, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, -95, -98, 67, -85,
-39, -11, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 98, -53, -8, 67,
-85, -21, -99, 68, 98, -10, -6, 67, -85, -21, -95, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 99, 2, -94, 67, -85, -21, -95, 0, 11, 32, 83, 69, 71, 95, 81,
85, 65, 68, 84, 79, 68, 98, -56, -104, 67, -85, -21, 61, 68, 98, -109, 28, 67, -85, -73,
-35, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, -91, -62, 67, -85,
-55, -22, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 99, -82, -62, 67,
-89, -125, 126, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 99, -100, 28,
67, -89, 113, 113, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 99, 83,
-6, 67, -89, 44, 5, 68, 99, 2, -94, 67, -89, 43, -95, 0, 11, 32, 83, 69, 71, 95,
76, 73, 78, 69, 84, 79, 68, 98, -10, -6, 67, -89, 43, -95, 0, 11, 32, 83, 69, 71,
95, 81, 85, 65, 68, 84, 79, 68, 99, 10, -82, 67, -89, 43, -91, 68, 99, 29, -72, 67,
-89, 51, -113, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 99, 18, 16,
67, -89, 46, -79, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 98, -25,
-73, 67, -89, 29, 9, 68, 98, -84, 99, 67, -89, 29, 5, 0, 11, 32, 83, 69, 71, 95,
76, 73, 78, 69, 84, 79, 68, 98, -112, 107, 67, -89, 29, 5, 0, 11, 32, 83, 69, 71,
95, 81, 85, 65, 68, 84, 79, 68, 98, 78, 121, 67, -89, 28, -15, 68, 98, 29, -110, 67,
-89, 53, -27, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, 6, 66,
67, -89, 65, -42, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, -100,
-76, 67, -85, -36, 6, 0, 10, 32, 83, 69, 71, 95, 67, 76, 79, 83, 69,};
public static final byte[] shapeAdded = {
0, 11, 32, 83, 69, 71, 95, 77, 79, 86, 69, 84, 79, 68, 102, 54, -63, 67, -84, -102,
29, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 96, -120, 114, 67, -94,
2, 48, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 94, -119, 0, 67,
-86, 67, -25, 0, 10, 32, 83, 69, 71, 95, 67, 76, 79, 83, 69,};
public static void main(String[] args) {
// Reversing the order of these try blocks has no effect.
try {
testAdd();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (OutOfMemoryError oome) {
System.gc();
oome.printStackTrace();
}
try {
testSubtract();
} catch (IOException e) {
e.printStackTrace();
} catch (OutOfMemoryError oome) {
System.gc();
oome.printStackTrace();
}
}
private static void testSubtract() throws IOException
{
Shape lineShape = loadShape(strokedLineToSubtract, "Line");
Shape negShape = loadShape(negSpace, "Space");
Area lineArea = new Area(lineShape);
Area negArea = new Area(negShape);
System.err.println("Attempting to subtract ... ");
lineArea.subtract(negArea); // This is what throws the OutOfMemoryError
System.err.println("Subtraction succeeded.");
}
private static void testAdd() throws IOException
{
Shape lineShape = loadShape(strokedLineToAdd, "Line");
Shape negShape = loadShape(shapeAdded, "Space");
Area lineArea = new Area(lineShape);
Area negArea = new Area(negShape);
System.err.println("Attempting to add ... ");
lineArea.add(negArea); // This is what throws the OutOfMemoryError
System.err.println("Addition succeeded.");
}
/**
* Although this method isn't used by this test case, this is the method
* used to create the two data sets that the test case uses.
* @param name The name to give to the variable
* @param shape
*/
public static void saveShapeData(Shape shape, String name)
{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
DataOutputStream os = new DataOutputStream(byteStream);
try {
saveShapeToStream(shape, os);
System.out.println("\npublic static final byte[] " + name + " = {\n");
byte[] data = byteStream.toByteArray();
int ii=0;
for (byte bt : data)
System.out.print(" " + Byte.toString(bt) + "," + ((++ii)%20==0? "\n":""));
System.out.println("};");
} catch (IOException e) {
e.printStackTrace();
}
}
private static void saveShapeToStream(Shape shape, DataOutputStream pOs) throws IOException {
PathIterator iter = shape.getPathIterator(null);
float[] coords = new float[6];
while(!iter.isDone()) {
int type = iter.currentSegment(coords);
switch(type) {
case PathIterator.SEG_CLOSE:
pOs.writeUTF(SEG_CLOSE);
break;
case PathIterator.SEG_CUBICTO:
pOs.writeUTF(SEG_CUBICTO);
for (float coord : coords)
pOs.writeFloat(coord);
break;
case PathIterator.SEG_LINETO:
pOs.writeUTF(SEG_LINETO);
pOs.writeFloat(coords[0]);
pOs.writeFloat(coords[1]);
break;
case PathIterator.SEG_MOVETO:
pOs.writeUTF(SEG_MOVETO);
pOs.writeFloat(coords[0]);
pOs.writeFloat(coords[1]);
break;
case PathIterator.SEG_QUADTO:
pOs.writeUTF(SEG_QUADTO);
for (int ii=0; ii<4; ++ii)
pOs.writeFloat(coords[ii]);
break;
default:
System.err.print(" UNKNOWN:" + type);
break;
}
iter.next();
}
}
public static Shape loadShape(byte[] fileData, String name) throws IOException
{
System.out.println("\n\n" + name + ":");
GeneralPath path = new GeneralPath();
path.setWindingRule(GeneralPath.WIND_NON_ZERO);
DataInputStream is=null;
is = new DataInputStream(new ByteArrayInputStream(fileData));
float[] coords = new float[6];
while (is.available()>0)
{
String type = is.readUTF();
System.out.print("\n" + type + "\n ");
if (type.equals(SEG_CLOSE)) {
path.closePath();
} else if (type.equals(SEG_CUBICTO)) {
for (int ii=0; ii<6; ++ii)
coords[ii] = readFloat(is);
path.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
} else if (type.equals(SEG_LINETO)) {
for (int ii=0; ii<2; ++ii)
coords[ii] = readFloat(is);
path.lineTo(coords[0], coords[1]);
} else if (type.equals(SEG_MOVETO)) {
for (int ii=0; ii<2; ++ii)
coords[ii] = readFloat(is);
path.moveTo(coords[0], coords[1]);
} else if (type.equals(SEG_QUADTO)) {
for (int ii=0; ii<4; ++ii)
coords[ii] = readFloat(is);
path.quadTo(coords[0], coords[1], coords[2], coords[3]);
}
}
return path;
}
/**
* This call reads all the float values and prints them out.
* @param is
* @return
* @throws IOException
*/
private static float readFloat(DataInputStream is) throws IOException
{
float ft = is.readFloat();
System.out.print("" + ft + ", ");
return ft;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Don't use PathIterator.SEG_QUADTO when creating the Shape. Bezier curves
work fine.
java version "1.5.0_05"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
The methods Area.add() and Area.subtract() sometimes causes an
OutOfMemoryError. This can happen when the Shape used to create
the area was created using the PathIterator.SEG_QUADTO constant.
Although this doesn't happen very often, it can be reliably
reproduced. In five minutes of running our test data, we drew 200
graphs, which made use of 247398 additions and 247399 subtractions of
areas made from 533510 SET_QUADTO curves, and encountered this bug
four times, twice with adding and twice with subtracting. Since this
makes it nearly certain that our customers will see the bug, we need
a fix, in spite of its seemingly rare nature. (Don't think of this as
four errors in 247,000 cases, think of it as 4 errors in 200 cases.)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Build and run the test case provided.
The program will load two shapes and create Areas. It will print out
the parameters to the GeneralPath methods it calls to make those
shapes. Then it will print out "Attempting to add..." then it
will try to subtract one area from the other.
It then will repeat this process with two new areas and attempt to subtract them.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The add and subtract should succeed, and the program should exit cleanly after
printing out "Addition succeeded" and "Subtraction succeeded." It shouldn't
take more than a second.
ACTUAL -
The program hangs for ten seconds or so, then prints out
"java.lang.OutOfMemoryError: Java heap space" for both the addition and the
subtraction.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.OutOfMemoryError: Java heap space
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.PathIterator;
import java.awt.geom.GeneralPath;
import java.io.*;
public class AreaSubtractBug {
public static final String SEG_CLOSE = " SEG_CLOSE";
public static final String SEG_CUBICTO = " SEG_CUBICTO";
public static final String SEG_LINETO = " SEG_LINETO";
public static final String SEG_MOVETO = " SEG_MOVETO";
public static final String SEG_QUADTO = " SEG_QUADTO";
public static final byte[] strokedLineToSubtract = {
0, 11, 32, 83, 69, 71, 95, 77, 79, 86, 69, 84, 79, 68, 117, 7, -63, 67, 15, 6,
87, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, 31, 16, 67, 15,
23, 5, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 117, 68, -12, 67,
15, 50, 54, 68, 117, 103, 16, 67, 15, 50, 59, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 117, 110, 14, 67, 15, 50, 59, 0, 11, 32, 83, 69, 71, 95, 81,
85, 65, 68, 84, 79, 68, 117, -56, 26, 67, 15, 48, -15, 68, 118, 22, 75, 67, 14, 112,
95, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 118, 61, 115, 67, 14,
15, 10, 68, 118, 94, 93, 67, 13, 127, -74, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78,
69, 84, 79, 68, 118, 103, -80, 67, 13, 87, 15, 0, 11, 32, 83, 69, 71, 95, 81, 85,
65, 68, 84, 79, 68, 118, 21, -76, 67, 14, -81, -105, 68, 117, -100, -84, 67, 14, -72, 72,
0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, -88, 84, 67, 14, -72,
72, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 117, 108, 85, 67, 14,
-73, 106, 68, 117, 53, 117, 67, 14, 74, -61, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78,
69, 84, 79, 68, 117, 72, 27, 67, 14, 112, 14, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 118, 87, -51, 67, 5, -16, 100, 0, 11, 32, 83, 69, 71, 95, 76,
73, 78, 69, 84, 79, 68, 118, 69, 39, 67, 5, -53, 25, 0, 11, 32, 83, 69, 71, 95,
81, 85, 65, 68, 84, 79, 68, 117, -5, -93, 67, 5, 57, 38, 68, 117, -88, 84, 67, 5,
56, 72, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, -100, -84, 67,
5, 56, 72, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 117, 12, 86,
67, 5, 64, -7, 68, 116, -89, -76, 67, 6, -22, -51, 0, 11, 32, 83, 69, 71, 95, 76,
73, 78, 69, 84, 79, 68, 116, -98, 97, 67, 7, 19, 116, 0, 11, 32, 83, 69, 71, 95,
81, 85, 65, 68, 84, 79, 68, 116, -75, -100, 67, 6, -83, -7, 68, 116, -44, -9, 67, 6,
95, -59, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 117, 26, -119, 67,
5, -76, 14, 68, 117, 110, 14, 67, 5, -78, 59, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 117, 103, 16, 67, 5, -78, 59, 0, 11, 32, 83, 69, 71, 95, 81,
85, 65, 68, 84, 79, 68, 117, 122, -71, 67, 5, -78, 22, 68, 117, -119, -60, 67, 5, -68,
-61, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, 114, 117, 67, 5,
-84, 21, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, 7, -63, 67,
15, 6, 87, 0, 10, 32, 83, 69, 71, 95, 67, 76, 79, 83, 69,};
public static final byte[] negSpace = {
0, 11, 32, 83, 69, 71, 95, 77, 79, 86, 69, 84, 79, 68, 116, -33, -12, 67, 4, 30,
-23, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 118, 59, 73, 67, 6,
-43, -109, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 117, 100, -97, 67,
13, -118, -32, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 116, 9, 75,
67, 10, -44, 54, 0, 10, 32, 83, 69, 71, 95, 67, 76, 79, 83, 69,};
public static final byte[] strokedLineToAdd = {
0, 11, 32, 83, 69, 71, 95, 77, 79, 86, 69, 84, 79, 68, 98, -100, -76, 67, -85, -36,
6, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, -76, 4, 67, -85,
-48, 21, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 98, -102, -29, 67,
-85, -36, -5, 68, 98, -112, 107, 67, -85, -35, 5, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 98, -84, 99, 67, -85, -35, 5, 0, 11, 32, 83, 69, 71, 95, 81,
85, 65, 68, 84, 79, 68, 98, -87, 1, 67, -85, -35, 1, 68, 98, -107, -10, 67, -85, -43,
23, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, -95, -98, 67, -85,
-39, -11, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 98, -53, -8, 67,
-85, -21, -99, 68, 98, -10, -6, 67, -85, -21, -95, 0, 11, 32, 83, 69, 71, 95, 76, 73,
78, 69, 84, 79, 68, 99, 2, -94, 67, -85, -21, -95, 0, 11, 32, 83, 69, 71, 95, 81,
85, 65, 68, 84, 79, 68, 98, -56, -104, 67, -85, -21, 61, 68, 98, -109, 28, 67, -85, -73,
-35, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, -91, -62, 67, -85,
-55, -22, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 99, -82, -62, 67,
-89, -125, 126, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 99, -100, 28,
67, -89, 113, 113, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 99, 83,
-6, 67, -89, 44, 5, 68, 99, 2, -94, 67, -89, 43, -95, 0, 11, 32, 83, 69, 71, 95,
76, 73, 78, 69, 84, 79, 68, 98, -10, -6, 67, -89, 43, -95, 0, 11, 32, 83, 69, 71,
95, 81, 85, 65, 68, 84, 79, 68, 99, 10, -82, 67, -89, 43, -91, 68, 99, 29, -72, 67,
-89, 51, -113, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 99, 18, 16,
67, -89, 46, -79, 0, 11, 32, 83, 69, 71, 95, 81, 85, 65, 68, 84, 79, 68, 98, -25,
-73, 67, -89, 29, 9, 68, 98, -84, 99, 67, -89, 29, 5, 0, 11, 32, 83, 69, 71, 95,
76, 73, 78, 69, 84, 79, 68, 98, -112, 107, 67, -89, 29, 5, 0, 11, 32, 83, 69, 71,
95, 81, 85, 65, 68, 84, 79, 68, 98, 78, 121, 67, -89, 28, -15, 68, 98, 29, -110, 67,
-89, 53, -27, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, 6, 66,
67, -89, 65, -42, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 98, -100,
-76, 67, -85, -36, 6, 0, 10, 32, 83, 69, 71, 95, 67, 76, 79, 83, 69,};
public static final byte[] shapeAdded = {
0, 11, 32, 83, 69, 71, 95, 77, 79, 86, 69, 84, 79, 68, 102, 54, -63, 67, -84, -102,
29, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 96, -120, 114, 67, -94,
2, 48, 0, 11, 32, 83, 69, 71, 95, 76, 73, 78, 69, 84, 79, 68, 94, -119, 0, 67,
-86, 67, -25, 0, 10, 32, 83, 69, 71, 95, 67, 76, 79, 83, 69,};
public static void main(String[] args) {
// Reversing the order of these try blocks has no effect.
try {
testAdd();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (OutOfMemoryError oome) {
System.gc();
oome.printStackTrace();
}
try {
testSubtract();
} catch (IOException e) {
e.printStackTrace();
} catch (OutOfMemoryError oome) {
System.gc();
oome.printStackTrace();
}
}
private static void testSubtract() throws IOException
{
Shape lineShape = loadShape(strokedLineToSubtract, "Line");
Shape negShape = loadShape(negSpace, "Space");
Area lineArea = new Area(lineShape);
Area negArea = new Area(negShape);
System.err.println("Attempting to subtract ... ");
lineArea.subtract(negArea); // This is what throws the OutOfMemoryError
System.err.println("Subtraction succeeded.");
}
private static void testAdd() throws IOException
{
Shape lineShape = loadShape(strokedLineToAdd, "Line");
Shape negShape = loadShape(shapeAdded, "Space");
Area lineArea = new Area(lineShape);
Area negArea = new Area(negShape);
System.err.println("Attempting to add ... ");
lineArea.add(negArea); // This is what throws the OutOfMemoryError
System.err.println("Addition succeeded.");
}
/**
* Although this method isn't used by this test case, this is the method
* used to create the two data sets that the test case uses.
* @param name The name to give to the variable
* @param shape
*/
public static void saveShapeData(Shape shape, String name)
{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
DataOutputStream os = new DataOutputStream(byteStream);
try {
saveShapeToStream(shape, os);
System.out.println("\npublic static final byte[] " + name + " = {\n");
byte[] data = byteStream.toByteArray();
int ii=0;
for (byte bt : data)
System.out.print(" " + Byte.toString(bt) + "," + ((++ii)%20==0? "\n":""));
System.out.println("};");
} catch (IOException e) {
e.printStackTrace();
}
}
private static void saveShapeToStream(Shape shape, DataOutputStream pOs) throws IOException {
PathIterator iter = shape.getPathIterator(null);
float[] coords = new float[6];
while(!iter.isDone()) {
int type = iter.currentSegment(coords);
switch(type) {
case PathIterator.SEG_CLOSE:
pOs.writeUTF(SEG_CLOSE);
break;
case PathIterator.SEG_CUBICTO:
pOs.writeUTF(SEG_CUBICTO);
for (float coord : coords)
pOs.writeFloat(coord);
break;
case PathIterator.SEG_LINETO:
pOs.writeUTF(SEG_LINETO);
pOs.writeFloat(coords[0]);
pOs.writeFloat(coords[1]);
break;
case PathIterator.SEG_MOVETO:
pOs.writeUTF(SEG_MOVETO);
pOs.writeFloat(coords[0]);
pOs.writeFloat(coords[1]);
break;
case PathIterator.SEG_QUADTO:
pOs.writeUTF(SEG_QUADTO);
for (int ii=0; ii<4; ++ii)
pOs.writeFloat(coords[ii]);
break;
default:
System.err.print(" UNKNOWN:" + type);
break;
}
iter.next();
}
}
public static Shape loadShape(byte[] fileData, String name) throws IOException
{
System.out.println("\n\n" + name + ":");
GeneralPath path = new GeneralPath();
path.setWindingRule(GeneralPath.WIND_NON_ZERO);
DataInputStream is=null;
is = new DataInputStream(new ByteArrayInputStream(fileData));
float[] coords = new float[6];
while (is.available()>0)
{
String type = is.readUTF();
System.out.print("\n" + type + "\n ");
if (type.equals(SEG_CLOSE)) {
path.closePath();
} else if (type.equals(SEG_CUBICTO)) {
for (int ii=0; ii<6; ++ii)
coords[ii] = readFloat(is);
path.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
} else if (type.equals(SEG_LINETO)) {
for (int ii=0; ii<2; ++ii)
coords[ii] = readFloat(is);
path.lineTo(coords[0], coords[1]);
} else if (type.equals(SEG_MOVETO)) {
for (int ii=0; ii<2; ++ii)
coords[ii] = readFloat(is);
path.moveTo(coords[0], coords[1]);
} else if (type.equals(SEG_QUADTO)) {
for (int ii=0; ii<4; ++ii)
coords[ii] = readFloat(is);
path.quadTo(coords[0], coords[1], coords[2], coords[3]);
}
}
return path;
}
/**
* This call reads all the float values and prints them out.
* @param is
* @return
* @throws IOException
*/
private static float readFloat(DataInputStream is) throws IOException
{
float ft = is.readFloat();
System.out.print("" + ft + ", ");
return ft;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Don't use PathIterator.SEG_QUADTO when creating the Shape. Bezier curves
work fine.
- duplicates
-
JDK-6398602 Constructing Area from valid path can contain NaN values
-
- Resolved
-