[Ikvm-developers] memory leak on C# side when using JAVA transient static objects
Brought to you by:
jfrijters
|
From: Boilay, V. <Vin...@sw...> - 2007-02-27 09:56:35
|
Hello
=20
I found a leak in my C# code using IKVM'ized version of the following
BasisPoint java class.
=20
It leaks like hell when calling toString on the C# side of things.
=20
It keeps allocating memory in the text.FieldPosition due to call to
text.NumberFormat due to call to DecimalFormat.
It seems that the transient static is not converted properly to a static
variable in here but is rather allocated each time and never released
form the heap.
=3D>
private transient static final NumberFormat PERCENT_FORMAT =
=3D
new DecimalFormat("#.0000");
private transient static final NumberFormat BP_FORMAT =3D =
new
DecimalFormat("##.00");
<=3D
=20
Very easy to reproduce on c# side by doing :
=20
for (long i =3D 0; i < 10000000; i++)
{
BasisPoint bp =3D BasisPoint.fromPercent(4);
s =3D bp.toString();
counter++;
if (i%50=3D=3D0)
Thread.Sleep(50)
}
=20
And you'll see memory growing, growing and growing
=20
PS: I ran the same for() test on pure java side and it does not leak.
=20
=20
import java.io.Serializable;
import java.text.DecimalFormat;
import java.text.NumberFormat;
=20
public final class BasisPoint implements Comparable, Serializable {
=20
private final int value;
private static final double SCALE =3D 100000.0;
private static final double PERCENT =3D 100.0;
private static final double PERCENT_SCALE =3D PERCENT * =
SCALE;
=20
private transient static final NumberFormat PERCENT_FORMAT =
=3D
new DecimalFormat("#.0000");
private transient static final NumberFormat BP_FORMAT =3D =
new
DecimalFormat("##.00");
=20
public static final BasisPoint ZERO =3D new BasisPoint(0);
=20
public static final BasisPoint NULL =3D new
BasisPoint(Integer.MIN_VALUE);
=20
private BasisPoint(final int value) {
this.value =3D value;
}
=20
=20
public String toString() {
if (isEmpty()) {
return " - ";
}
if (isSubPercent()) {
return displayInBasisPoint();
} else {
return displayInPercent();
}
}
=20
public String displayInBasisPoint() {
return BP_FORMAT.format(basisPointValue()) +
"bp";
}
=20
public String displayInPercent() {
return PERCENT_FORMAT.format(percentValue()) +
"%";
}
=20
public static BasisPoint fromPercent(double percent) {
return fromBasisPoint(percent * PERCENT);
}
=20
public static BasisPoint fromBasisPoint(double basisPoint) {
int bp =3D (int) Math.round(basisPoint * SCALE);
return new BasisPoint(bp);
}
=20
public double basisPointValue() {
return (value =3D=3D 0) ? 0.0 : value / SCALE;
}
=20
public double percentValue() {
return (value =3D=3D 0) ? 0.0 : value /
PERCENT_SCALE;
}
=20
=20
public BasisPoint round(double coeff) {
int bp =3D (int) (Math.round(value / SCALE /
coeff) * SCALE * coeff);
return bp =3D=3D value ? this : new =
BasisPoint(bp);
}
=20
public boolean isSubPercent() {
return (value > 0) ? value < PERCENT_SCALE :
-value < PERCENT_SCALE;
}
=20
=20
public int compareTo(Object arg) {
if (!(arg instanceof BasisPoint)) {
throw new
IllegalArgumentException("Can only compare BasisPoint with BasisPoint
instances");
}
BasisPoint other =3D (BasisPoint) arg;
if (value =3D=3D other.value) {
return 0;
}
return (value > other.value) ? 1 : -1;
}
=20
=20
public boolean equals(Object arg) {
if (this =3D=3D arg) {
return true;
}
if (!(arg instanceof BasisPoint)) {
return false;
}
BasisPoint other =3D (BasisPoint) arg;
return value =3D=3D other.value;
}
=20
public int hashCode() {
return value;
}
=20
}
|