我的火花工作正在创建许多小对象并遇到垃圾收集问题。我已经尝试了多种方法将double转换为具有10位精度的String而没有Scientific符号。
第一种方式
String.format("%.10f", denomValue)
此案例的错误:
java.lang.OutOfMemoryError: GC overhead limit exceeded
at sun.misc.FormattedFloatingDecimal.create(FormattedFloatingDecimal.java:254)
at sun.misc.FormattedFloatingDecimal.fillDecimal(FormattedFloatingDecimal.java:267)
at sun.misc.FormattedFloatingDecimal.<init>(FormattedFloatingDecimal.java:76)
at sun.misc.FormattedFloatingDecimal.valueOf(FormattedFloatingDecimal.java:38)
at java.util.Formatter$FormatSpecifier.print(Formatter.java:3298)
at java.util.Formatter$FormatSpecifier.print(Formatter.java:3238)
at java.util.Formatter$FormatSpecifier.printFloat(Formatter.java:2802)
at java.util.Formatter$FormatSpecifier.print(Formatter.java:2753)
at java.util.Formatter.format(Formatter.java:2520)
at java.util.Formatter.format(Formatter.java:2455)
at java.lang.String.format(String.java:2925)
第二种方式
new BigDecimal(d).setScale(10,BigDecimal.ROUND_UP).toPlainString()
这种情况的错误: -
java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.math.MutableBigInteger.divideMagnitude(MutableBigInteger.java:1489)
at java.math.MutableBigInteger.divideKnuth(MutableBigInteger.java:1227)
at java.math.MutableBigInteger.divide(MutableBigInteger.java:1153)
at java.math.MutableBigInteger.divide(MutableBigInteger.java:1147)
at java.math.BigDecimal.divideAndRound(BigDecimal.java:4326)
at java.math.BigDecimal.setScale(BigDecimal.java:2470)
答案 0 :(得分:1)
引用&#34; Understand the OutOfMemoryError Exception&#34;:
thread thread_name中的异常:java.lang.OutOfMemoryError:超出GC开销限制
原因:详细消息&#34; GC开销限制超出&#34;表示垃圾收集器一直在运行,Java程序进展非常缓慢。在垃圾收集之后,如果Java进程花费超过大约98%的时间进行垃圾收集,并且它正在恢复少于2%的堆并且到目前为止已经执行了最后5个(编译时常量)连续垃圾集合,然后抛出java.lang.OutOfMemoryError。通常会抛出此异常,因为实时数据量几乎不适合Java堆,新分配的可用空间很小。
操作:增加堆大小。可以使用命令行标志-XX:-UseGCOverheadLimit关闭超出GC Overhead限制的java.lang.OutOfMemoryError异常。
如果您的代码真正花费98%的时间进行垃圾收集,那么您肯定应该增加堆大小,因为这意味着98%的内存用于(半)永久数据,少于2 %可以免费进行临时分配。
您可能遇到严重的内存泄漏问题。
但正如它所说,如果需要,您可以禁用该特定错误。
至于你的代码,你应该坚持使用选项1.选项2将创建更多垃圾选项1。
答案 1 :(得分:0)
我已经对少数意见进行了基准测试以格式化十进制数
在所有情况下,我都测量了内存浪费,以格式化一个十进制数。 以下是32 JVM的结果。
java.util.Formatter
Format mem usage: 1120
Format + string mem usage: 1184
java.text.DecimalFormat
Format + string mem usage: 288
org.apache.xmlgraphics.util.DoubleFormatUtil.formatDouble()
Format mem usage: 0
Format + string mem usage: 64
java.lang.String.format()
Format + string mem usage: 1448
代码低于
@Test
public void testDecimalFormat() {
double pi = Math.PI;
System.out.println("\njava.text.DecimalFormat");
DecimalFormat fmt = new DecimalFormat(".##########");
fmt.setRoundingMode(RoundingMode.UP);
// warm up
fmt.format(pi);
long mme = -(getCurrentThreadAllocatedBytes() - getCurrentThreadAllocatedBytes());
long memu1 = getCurrentThreadAllocatedBytes();
String val = fmt.format(pi);
long memu2 = getCurrentThreadAllocatedBytes();
System.out.println(val);
System.out.println("Format + string mem usage: " + (memu2 - memu1 - mme));
}
@Test
public void testFormatter() {
System.out.println("\njava.util.Formatter");
double pi = Math.PI;
StringBuilder sb = new StringBuilder(64);
Formatter ftm = new Formatter(sb);
// warm up
ftm.format("%.10f", pi);
sb.setLength(0);
// memory measurment error
long mme = -(getCurrentThreadAllocatedBytes() - getCurrentThreadAllocatedBytes());
long memu0 = getCurrentThreadAllocatedBytes();
ftm.format("%.10f", pi);
long memu1 = getCurrentThreadAllocatedBytes();
String val = sb.toString();
long memu2 = getCurrentThreadAllocatedBytes();
System.out.println(val);
System.out.println("Format mem usage: " + (memu1 - memu0 - mme));
System.out.println("Format + string mem usage: " + (memu2 - memu0 - 2 * mme));
}
@Test
public void testStringFormat() {
System.out.println("\njava.lang.String.format()");
double pi = Math.PI;
// warmup
String.format("%.10f", pi);
// memory measurment error
long mme = -(getCurrentThreadAllocatedBytes() - getCurrentThreadAllocatedBytes());
long memu1 = getCurrentThreadAllocatedBytes();
String val = String.format("%.10f", pi);
long memu2 = getCurrentThreadAllocatedBytes();
System.out.println(val);
System.out.println("Format + string mem usage: " + (memu2 - memu1 - mme));
}
@Test
public void testDoubleFormatUtil() {
System.out.println("\norg.apache.xmlgraphics.util.DoubleFormatUtil.formatDouble()");
double pi = Math.PI;
StringBuffer sb = new StringBuffer(64);
// warmup
DoubleFormatUtil.formatDouble(pi, 10, 10, sb);
sb.setLength(0);
// memory measurment error
long mme = -(getCurrentThreadAllocatedBytes() - getCurrentThreadAllocatedBytes());
long memu0 = getCurrentThreadAllocatedBytes();
DoubleFormatUtil.formatDouble(pi, 10, 10, sb);
long memu1 = getCurrentThreadAllocatedBytes();
String val = sb.toString();
long memu2 = getCurrentThreadAllocatedBytes();
System.out.println(val);
System.out.println("Format mem usage: " + (memu1 - memu0 - mme));
System.out.println("Format + string mem usage: " + (memu2 - memu0 - 2 * mme));
}
private long getCurrentThreadAllocatedBytes() {
return ((com.sun.management.ThreadMXBean)ManagementFactory.getThreadMXBean()).getThreadAllocatedBytes(Thread.currentThread().getId());
}