Android 算术计算器中的垃圾收集过多
我正在尝试创建一个Android应用程序,它可以绘制用户输入的简单数学函数(本质上是一个图形计算器)。 每个onDraw调用每秒需要数百次算术求值(这些求值被绘制在屏幕上以生成图形)。当我的代码对表达式求值时,程序的速度会大大减慢;当内置方法对表达式求值时,应用程序运行时不会出现问题 根据LogCat的说法,垃圾收集大约每秒发生12次,每次暂停应用程序大约15毫秒,导致每秒数百毫秒的冻结。我认为这就是问题所在 这是我的evaluator函数的一个提炼版本。要计算的表达式名为“postfixEquation”,字符串ArrayList“list”在过程结束时保存最终答案。还有两个名为“数字”和“运算符”的字符串数组,用于存储能够使用的数字和符号:Android 算术计算器中的垃圾收集过多,android,garbage-collection,Android,Garbage Collection,我正在尝试创建一个Android应用程序,它可以绘制用户输入的简单数学函数(本质上是一个图形计算器)。 每个onDraw调用每秒需要数百次算术求值(这些求值被绘制在屏幕上以生成图形)。当我的代码对表达式求值时,程序的速度会大大减慢;当内置方法对表达式求值时,应用程序运行时不会出现问题 根据LogCat的说法,垃圾收集大约每秒发生12次,每次暂停应用程序大约15毫秒,导致每秒数百毫秒的冻结。我认为这就是问题所在 这是我的evaluator函数的一个提炼版本。要计算的表达式名为“postfixEqu
String evaluate(String[] postfixEquation) {
list.clear();
for (int i = 0; i < postfixEquation.length; i++) {
symbol = postfixEquation[i];
// If the first character of our symbol is a digit, our symbol is a numeral
if (Arrays.asList(digits).contains(Character.toString(symbol.charAt(0)))) {
list.add(symbol);
} else if (Arrays.asList(operators).contains(symbol)) {
// There must be at least 2 numerals to operate on
if (list.size() < 2) {
return "Error, Incorrect operator usage.";
}
// Operates on the top two numerals of the list, then removes them
// Adds the answer of the operation to the list
firstItem = Double.parseDouble(list.get(list.size() - 1));
secondItem = Double.parseDouble(list.get(list.size() - 2));
list.remove(list.size() - 1);
list.remove(list.size() - 1);
if (symbol.equals(operators[0])){
list.add( Double.toString(secondItem - firstItem) );
} else if (symbol.equals(operators[1])) {
list.add( Double.toString(secondItem + firstItem) );
} else if (symbol.equals(operators[2])) {
list.add( Double.toString(secondItem * firstItem) );
} else if (symbol.equals(operators[3])) {
if (firstItem != 0) {
list.add( Double.toString(secondItem / firstItem) );
} else {
return "Error, Dividing by 0 is undefined.";
}
} else {
return "Error, Unknown symbol '" + symbol + "'.";
}
}
}
// The list should contain a single item, the final answer
if (list.size() != 1) {
return "Error, " + list has " + list.size() + " items left instead of 1.";
}
// All is fine, return the final answer
return list.get(0);
}
String求值(String[]postfix方程){
list.clear();
for(int i=0;i
操作中使用的数字都是字符串,因为我不确定是否可以在一个数组中保存多个类型(即字符串和Double),因此出现了大量的“Double.parseDouble”和“Double.toString”调用
如何减少此处发生的垃圾收集量?
如果有帮助的话,我一直在使用以下步骤来计算我的后缀表达式:。
我已经好几个星期没有解决这个问题了。如果您能提供任何帮助,我们将不胜感激。谢谢。可能是您的列表操作导致了这个问题。列表内部有数组,数组会根据列表中的数据量进行扩展/收缩。因此,随机进行大量添加和删除操作将非常需要垃圾收集离子 避免这种情况的解决方案是使用正确的
List
实现。对于您的问题,请在开始时为列表分配足够的空间,以避免调整内部数组的大小,并标记未使用的元素,而不是删除它们
冻结症状是因为您正在您的应用程序中进行计算。如果您不希望您的应用程序冻结,您可能需要在单独的线程上检查以执行计算
PS:看起来你在做一些无用的操作……为什么
parseDouble()
secondItem
?Java中的紧循环规则是不分配任何东西。你看到如此频繁的GC收集就是证明
您似乎是在使用双精度
进行计算,然后将其转换为字符串
。不要这样做,这对性能很糟糕,因为您创建了大量的字符串,然后将其丢弃(另外,您在字符串和双精度之间来回转换了很多)。只需维护一个ArrayDeque
,并将其用作堆栈即可--这还可以避免执行可能会降低性能的数组大小调整
预编译输入公式。将所有输入操作转换为enum
实例——它们比较起来更快(只需使用开关
语句),甚至可能使用更少的内存。如果您需要处理double,可以使用通用的对象
容器和实例
,或者使用包含操作枚举
和double
的容器类。预编译可以避免在紧循环中进行昂贵的测试
如果你做这些事情,你的循环肯定会飞。 在你的UI线程中没有发生15MS停顿,所以它们不应该对性能有很大影响。如果你的UI在你的方法正在执行时暂停,那么考虑在另一个线程上运行它(用AsyncTask) 要减少垃圾收集,您需要减少循环中分配的内存量 我建议