Java - 内存分配困难(GC_FOR_ALLOC)

3

当我启动这个线程时,我的Android应用程序崩溃了。

这个线程应该重新启动手机。但当我启动它时,它并没有重新启动手机,并且在日志中出现了以下文本:

08-25 09:12:00.946 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: GC_FOR_ALLOC释放了1279K (30823),内存使用率为55%,剩余4485K/9968K,暂停时间53ms,总时间53ms。08-25 09:12:01.294 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: 上一次GC分配之间的空间为1280K。08-25 09:12:01.346 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: GC_FOR_ALLOC释放了1280K (30820),内存使用率为55%,剩余4485K/9968K,暂停时间52ms,总时间52ms。08-25 09:12:01.713 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: 上一次GC分配之间的空间为1279K。08-25 09:12:01.768 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: GC_FOR_ALLOC释放了1279K (30813),内存使用率为55%,剩余4486K/9968K,暂停时间55ms,总时间55ms。08-25 09:12:02.111 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: 上一次GC分配之间的空间为1279K。08-25 09:12:02.164 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: GC_FOR_ALLOC释放了1280K (30819),内存使用率为55%,剩余4486K/9968K,暂停时间53ms,总时间53ms。08-25 09:12:02.504 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: 上一次GC分配之间的空间为1279K。08-25 09:12:02.557 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: GC_FOR_ALLOC释放了1280K (30823),内存使用率为55%,剩余4485K/9968K,暂停时间53ms,总时间53ms。08-25 09:12:02.901 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: 上一次GC分配之间的空间为1279K。08-25 09:12:02.956 26029-26813/com.datasulting.chris.smsgateway D/dalvikvm: GC_FOR_ALLOC释放了1279K (30818),内存使用率为55%,剩余4485K/9968K,暂停时间55ms,总时间55ms。
这是我的线程。
class Reboot implements Runnable {

    private volatile boolean cancelled;
    Boolean checkRebootHeb;
    Boolean checkRebootQuo;
    int jourDemandeeInt;
    String jourDemandeeString;
    String weekDay;
    int dayOfWeek;
    SimpleDateFormat df;
    String heure;
    String dayOfWeekString;
    String heureDemandee;
    Calendar c;

    public Reboot(Boolean VARcheckReboot, Boolean VARcheckRebootQuo, int VARjour, String VARtextReboot) {
        checkRebootHeb = VARcheckReboot;
        checkRebootQuo = VARcheckRebootQuo;
        jourDemandeeInt = VARjour;
        heureDemandee = VARtextReboot;
    }


    @Override
    public void run() {

        while (!cancelled) {

            if (jourDemandeeInt == 0){
                jourDemandeeString = "Lundi";
            }
            if (jourDemandeeInt == 1){
                jourDemandeeString = "Mardi";
            }
            if (jourDemandeeInt == 2){
                jourDemandeeString = "Mercredi";
            }
            if (jourDemandeeInt == 3){
                jourDemandeeString = "Jeudi";
            }
            if (jourDemandeeInt == 4){
                jourDemandeeString = "Vendredi";
            }
            if (jourDemandeeInt == 5){
                jourDemandeeString = "Samedi";
            }
            if (jourDemandeeInt == 6){
                jourDemandeeString = "Dimanche";
            }

            c = Calendar.getInstance();
            dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
            df = new SimpleDateFormat("HH:mm");
            heure = df.format(c.getTime());


            if (Calendar.MONDAY == dayOfWeek) weekDay = "Lundi";
            else if (Calendar.TUESDAY == dayOfWeek) weekDay = "Mardi";
            else if (Calendar.WEDNESDAY == dayOfWeek) weekDay = "Mercredi";
            else if (Calendar.THURSDAY == dayOfWeek) weekDay = "Jeudi";
            else if (Calendar.FRIDAY == dayOfWeek) weekDay = "Vendredi";
            else if (Calendar.SATURDAY == dayOfWeek) weekDay = "Samedi";
            else if (Calendar.SUNDAY == dayOfWeek) weekDay = "Dimanche";


            dayOfWeekString = String.valueOf(dayOfWeek);

            if (checkRebootQuo == true) {
                if (heure.equals(heureDemandee)) {
                    try {

                        Process proc = Runtime.getRuntime().exec(new String[]{"su", "-c", "reboot"});
                        proc.waitFor();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }

            if (checkRebootHeb == true) {
                if (dayOfWeekString.equals(jourDemandeeString)) {
                    if (heure.equals(heureDemandee)) {
                        try {

                            Process proc = Runtime.getRuntime().exec(new String[]{"su", "-c", "reboot"});
                            proc.waitFor();
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }

        }


    }

    public void cancel() {
        cancelled = true;
    }
}

非常感谢,对于我的英语不好请见谅 :p - Christophe Hugueny
1个回答

0

这段代码有很多问题。

你的主要问题是:线程正在进行“主动”等待。这意味着:它只是循环并创建一个新的日历对象每次迭代。然后你立即丢弃该对象,并创建一个新对象。

你感到惊讶垃圾收集器难以处理你的代码吗?为了确保我的讽刺不会阻碍人们理解问题:世界上没有任何垃圾收集器被设计用于允许仅创建垃圾对象的“热”循环;特别是在“移动”世界中。

所以,显而易见的答案是:在循环体中添加一些Thread.sleep()语句,例如:

  • 检查是否需要重启
  • 如果是:重启
  • 如果不是:休眠一分钟
  • 重复

你的代码做了以下事情: - 检查是否需要重启 - 如果是:重启 - 重复

接下来,对你(抱歉)可怕的代码提供一些普遍反馈:

  • 把工作日转换成法语字符串进行比较,简直太疯狂了。你已经有一个表示周一的整数0了。只需要向日历对象查询星期几的整数值就可以了。你将0转换成"Lundi",然后再将0转换成"Lundi",以便进行字符串匹配。简直疯了。
  • 你的命名也很糟糕。真的,只用一种语言。我猜“checkRebootQuo”是关于每小时重启的,而“checkRebootHeb”则是关于每周重启的某种方式。如果你把变量重命名为“rebootHourly”和“rebootWeekly”……那将会更清晰明了。
  • 最后:不要使用多个布尔参数,然后在方法中使用多个IF语句。相反:使用多态性。有一个基类,知道如何循环和重启;然后有两个子类;一个知道如何在下一个小时重启,另一个知道如何在指定的星期几重启。

谢谢,但我不认为这会解决问题。这个线程有时会运行一整个星期。我认为这个解决方案可以解决问题,但只是暂时的。 - Christophe Hugueny
你遇到内存问题是因为你可能每分钟创建了数百万个对象。你不断地在触发垃圾回收。当你添加睡眠时,可以将新对象的数量减少到每分钟一个。你明白了吗? - GhostCat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接