精华内容
下载资源
问答
  • 程序死循环

    千次阅读 2016-12-08 16:39:04
      死循环是一个非常让人反感的问题,它 有时候是站在程序正常运行的外面下,进行着错误的行为,有时候很久才能发现这个问题。(而在这个过程中也会造成很大的损失)   容易造成损失的地方,人们就会尝试去解决...

    问题

      编程结束了,我们的程序跑起来了。但是我们不知道其是否能终止,结果是否正确等等。我们面临着一系列的问题。
      死循环是一个非常让人反感的问题,它 有时候是站在程序正常运行的外表下,进行着错误的行为,有时候很久才能发现这个问题。(而在这个过程中也会造成很大的损失)
      容易造成损失的地方,人们就会尝试去解决这些问题。
      为了避免这样的问题,人们开发了一些检测的方法,用来检测程序中可能存在死循环的地方。
    (这里主要指单线程)

    死循环的本质

      一段程序,能够陷入死循环,是因为具备了一定的死循环的条件的。

    • 环的存在】对于一段代码,构造出其语句流程图,那么环如果存在是形成死循环的一个必要的条件。(图1)
    • 关键结点】在一个环中并不是所有的结点对于死循环的形成都是同等重要的。那些处在跳出循环以及进入循环处的结点十分重要。(比如说,while,for循环中的条件判断成分,决定了循环的走向,条件控制的错误将会导致死循环的产生)


      PS:
    • 借鉴意义】当我们去查找一个死循环的问题的时候,要从循环体中的关键结点(控制条件处)入手进行分析。
    • 数据流简化】死循环是循环的一种非正常方式,控制逻辑的错误是导致这种问题的主要原因。(通过分析与条件相关的数据流链,我们能够从数据流角度,进一步缩小分析的范围,筛选出不在这条数据流上的一些东西,简化)

    图1:
    这里写图片描述

    简单举例

    关于下面代码的相关说明:

    • 循环结构的存在】for结构的存在,决定了环路的存在。
    • 关键控制点】关键控制点为 i <data。这句话直接决定了循环能否跳出,是否会进入死循环。
    • 数据流跟踪】在进行数据流跟踪的时候,我们只关注与i,data直接相关 或者 间接相关的语句,所以我们可以在分析时不考虑输出语句System.out.println(“the data is : ” + data);。所以我们定位到了data++这条语句。
        public static void testCycle(){
            int data = 5;
            for(int i=0;i<data;i++){//关键点1
                System.out.println("the data is : " + data);
                data++;//关键点2
            }
        }
    展开全文
  • ADS调试程序时进入死循环

    千次阅读 2010-04-25 22:36:00
    [现象]在用ARM的ADS调试的时候,在调试某一行看起来极其简单,应该不会出错的程序时候,按F8希望进入该函数,但是整个程序了,中断运行,显示的信息如下所示:DBE Warning 00056: The statement into which was stepped...

    [现象]

    在用ARM的ADS调试的时候,在调试某一行看起来极其简单,应该不会出错的程序时候,按F8希望进入该函数,但是整个程序却死了,中断运行,显示的信息如下所示:

    DBE Warning 00056: The statement into which was stepped is singular (i.e. it has no exit)

    经过调试,最终发现,是在执行此行程序之前,由于申请emWin的Memory Device,也就是申请一块内存的时候,由于堆内空闲空间不够,所以申请失败,所以获得的该memdev的指针也就为NULL了,而接着的memset操作,导致清空了不该清空的内容,好像是清空了0x0002C或者0x0000,往后一段空间,主要是中断向量表之类的内容,因此,在下面的执行之前,栈内的各个变量,如堆栈指针sp内容也都不对了,而且pc的值,也不对了,最后是PC的值为0,因此程序执行了reset,进入了死循环.

    [办法]

    将emWin的堆的空间大小的宏定义GUI_ALLOC_SIZE加大,重新编译emWin的库

    [总结]

    1.开始时候,看堆栈的sp有问题,怀疑是堆栈溢出,sp的值应该在0x3065073c -> 0x3064c73c之间,但是此时sp已经是0x00045C之类的值,显然不是溢出,而是被冲掉了.所以继续debug,才知道是申请memdev失败返回memdev指针对空,而后的memset,将0x0002C之后的一段代码清空所导致的问题.

    2.以后一定要记住,在申请空间后,一定要判断返回值是否为空.任何一处的返回值判断都不能少,否则就会出现严重时甚至会导致系统崩溃的问题....

    展开全文
  • Drools 规则引擎死循环问题解决

    千次阅读 2020-02-22 17:50:07
    在《Drools7 规则引擎视频教程》中已经讲到,使用modify或update的时候在某种程度上会导致死循环。 昨天一同学在使用Drools规则引擎时便遇到了该问题。下面看该同学贴出来的规则代码: 首先我们来分析一下上面的...

    在《Drools7 规则引擎视频教程》中已经讲到,使用modify或update的时候在某种程度上会导致死循环。

    昨天一同学在使用Drools规则引擎时便遇到了该问题。下面看该同学贴出来的规则代码:
    Drools规则引擎死循环
    首先我们来分析一下上面的代码,上面的代码中这位同学讲一个相同的Map,传递进入两个规则中,在规则的then部分中会对map的属性值进行更新。为了防止死循环他使用了no-loop属性。

    但是问题依旧存在。为什么呢?其实这跟no-loop使用的功能有关,no-loop的作用是限制因为modify等更新操作导致规则重复执行,但是有一个限定条件,是当前规则中进行更新导致当前规则重复执行。而不是防止其他规则更新相同的fact对象,导致当前规则更新。

    因此,针对以上问题,不仅仅要解决当前规则自身引起的更新,还需要解决其他规则更新fact对象引起的更新。这时还需要使用ock-on-active true属性配置。

    lock-on-active true这个属性,可以限制当前规则只会被执行一次,包括当前规则的重复执行不是本身触发的。是no-loop的加强版。

    另外,针对这段代码的编写,这位同学还犯了另外一个错误,就是When中的判断条件。两个规则中都用了两个判断条件。$map:Map()相当于一个判断条件;Map(…)又相当于一个判断条件。其实这两个判断条件应该合并成一个,如这样的形式:$map:Map(…)。大家在使用的过程中注意不要犯类似的错误。

    更多学习途径

    更多关于Drools规则引擎的视频教程和学习群组,访问此处

    帮你解决疑难问题,扫码加入Drools规则引擎星球:
    Drools规则引擎

    展开全文
  • 本文主要分析char型数值的错误取值导致程序陷入死循环的深层次原因。通过构造一个典型程序死循环问题,跟随本文思维方式,可以让读者从编译器角度深入理解错误原因,还能了解到编译器是如何对char型取值范围进行限制...

    一、问题

            本段代码有什么问题?如何修改?

    #include <iostream>
    using namespace std;
    
    #define MAX 255
    
    main()
    {
          char p[MAX+1];
          char ch;
          
          for (ch=0;ch<=MAX;ch++)
          {
              p[ch]=ch;
              cout<<ch<<" ";
              }
          cout<< ch<<" ";
    }
    解析:

        首先这段程序在运行时会陷入死循环,归其原因是代码中“char数值问题”。具体分析如下。

           1、char取值范围

           char类型占一字节(8位),取值范围为-128到127。如何得到的取值范围呢?具体如下:

           由于数字在计算机中是以补码形式表示,并且char类型为有符号数,则一字节(8位)中的最高位为符号位。能表示的最大正数二进制形式为“01111111”,由于正数补码与原码相同,其原码同样为“01111111”,对应十进制为127;同理,能表示的最小负数二进制形式为“10000000”,由于这是补码形式,其原码对应为“110000000”,对应十进制为-128。

           2、知道了char的取值范围,回过头看题目中代码的for循环语句,ch的取值从0到127这阶段的循环语句都很正常。当ch=128时,由于超出char取值范围,编译器会将ch值变为-128,仍然满足<=MAX条件,继续执行循环,同时ch++。由于每次for循环ch都自增(ch++),ch值将会逐渐从-128递增到0,这时又回到了for循环的起始条件处(ch=0),当再次递增到127后,ch值又会变为-128,以后不断循环。

           3、从以上分析中可以看出,“ch++”语句并没有使ch值一直增加,相反ch值不断在“-128到127”中循环变化,进而是“ch<=MAX”(MAX=255)永远成立,程序陷入死循环。

           下面,为了探究其根本原因,对程序进行调试,从编译器角度分析程序陷入死循环原因。

    深入分析:

           主要看程序中“for (ch=0;ch<=MAX;ch++)”和“p[ch]=ch;”语句的汇编代码:  

    for (ch=0;ch<=MAX;ch++)
    0040116E   mov         byte ptr [ebp-104h],0
    00401175   jmp         main+35h (00401185)
    00401177   mov         al,byte ptr [ebp-104h]
    0040117D   add         al,1
    0040117F   mov         byte ptr [ebp-104h],al
    00401185   movsx       ecx,byte ptr [ebp-104h]
    0040118C   cmp         ecx,0FFh
    00401192   jg          main+7Ch (004011cc)
    {
             p[ch]=ch;
    00401194   movsx       edx,byte ptr [ebp-104h]
    0040119B   mov         al,byte ptr [ebp-104h]
    004011A1   mov         byte ptr [ebp+edx-100h],al
         从汇编代码中可知,edx寄存器中存放的是ch值,[ebp+edx-100h]对应“char型数组p”下标。通过调试程序可知p[0]内存地址为0x0013fe80,p[1]内存地址为0x0013fe81,p[2]内存地址为0x0013fe82,……p[127]内存地址为0x0013feff。p[0]至p[127]内存布局如下图所示(其中127的十六进制表示为“0x7F”):


        p[0]到p[127],一切都很正常。当执行ch++后ch=128 时,就会出现问题,继续看汇编代码。

      for (ch=0;ch<=MAX;ch++)
    00401177   mov         al,byte ptr [ebp-104h]  //此时[ebp-104h]地址为0x13fe7c,对应数据为“0x7F”。
    0040117D   add         al,1
    0040117F   mov         byte ptr [ebp-104h],al  //执行自增操作后,结果写入内存[ebp-104h]地址处,也就是
                                                     说0x13fe7c处内容将变为“0x80”。
    00401185   movsx       ecx,byte ptr [ebp-104h] //将内存[ebp-104h]地址处内容符号扩展后传入ecx寄存器。

        看下执行这条语句后ecx寄存器中内容:


       对“0x80”进行符号扩展后变为“0xFFFFFF80”。这里有必要对movsx进行下说明,

    movsx:先符号位扩展,再传送。以“0x80”为例,二进制形式为“10000000”,符号扩展成32位后为“11111111111111111111111110000000”,十六进制为“0xFFFFFF80”。与movsx相对的有movzx,movzx:先零扩展再传送。

           这时ecx寄存器中的数据其值的十进制已变为-128。继续往下看汇编代码。

    {
           p[ch]=ch;
    0040118C   cmp         ecx,0FFh //-128确实小于255,执行循环体
    00401194   movsx       edx,byte ptr [ebp-104h] //同样将将内存[ebp-104h]地址处内容符号扩展后传入edx寄
                                                     存器。
    0040119B   mov         al,byte ptr [ebp-104h] 
    004011A1   mov         byte ptr [ebp+edx-100h],al //由于edx的内容为“-128”,此时[ebp+edx-100h]地址为
                                                        0x0013fe00。
           因此,al寄存器中的数据“0x80”将被写入内存0x0013fe00地址处。


        写入数据之后,程序再继续往下执行,由于数据写入的位置超出了程序之前给p[]申请的栈空间,而这部分内存空间之前的内容是cout函数地址。并且,在程序执行循环体中的“cout<<ch<<" "”代码时,会被用来存储临时数据,所以之前写入的p[ch]值,在执行一次for循环后会被清除掉,且其地址处的内容会恢复到程序开始时存入的cout函数地址。

           此时,ch=-128,继续执行for循环,同时ch自增(ch++),ch的值会从-128变到0,之后程序又会正常地将p[ch]值从内存地址0x0013fe80处开始依次写入,当ch增到127后,由于编译器的movsx操作又会将ch值变为-128,陷入死循环。

    总结:

           从编译器角度分析,出现这种循环的根本原因是,编译器使用“movsx”操作传值,由于ch是char型,当其值在0至127之间时,对应二进制数最高位为0,也就是符号位为正,使用movsx符号扩展后仍然为正,并且高位用都用0填充。当ch值大于等于128时,对应二进制最高位为1,也就是符号位为负,符号位扩展后仍然为负,并且高位都用1填充,这就是为什么ch自增到128时,编译器将将其值变为-128的根源。


    二、问题进阶

           如前面所述,char范围为-128至127,若将程序改成unsigned char型,还会陷入死循环吗?修改后的代码:

    #include <iostream>
    using namespace std;
    
    #define MAX 255
    
    main()
    {
          char p[MAX+1];
          unsigned char ch;  //修改成无符号char型
          
          for (ch=0;ch<=MAX;ch++)
          {
              p[ch]=ch;
              cout<<ch<<" ";
              }
          cout<< ch<<" ";
    }
         运行此程序,同样陷入死循环。Why?先来看下for循环部分的汇编代码:

    for (ch=0;ch<=MAX;ch++)
    0040116E   mov         byte ptr [ebp-104h],0
    00401175   jmp         main+35h (00401185)
    00401177   mov         al,byte ptr [ebp-104h]
    0040117D   add         al,1
    0040117F   mov         byte ptr [ebp-104h],al
    00401185   mov         ecx,dword ptr [ebp-104h]
    0040118B   and         ecx,0FFh
    00401191   cmp         ecx,0FFh
    00401197   jg          main+86h (004011d6)
    {
         p[ch]=ch;
    00401199   mov         edx,dword ptr [ebp-104h]
    0040119F   and         edx,0FFh
    004011A5   mov         al,byte ptr [ebp-104h]
    004011AB   mov         byte ptr [ebp+edx-100h],al
               可以看出将ch设置成unsigned char后的汇编代码与设置成char的汇编代码有少量不同。在unsigned char版本中编译器没有使用movsx指令。在ch与MAX作比较时,char版本使用“movsx       ecx,byte ptr [ebp-104h]”代码对[ebp-104h]地址取一字节放入ecx寄存器中,而unsigned char版本使用“mov         ecx,dword ptr [ebp-104h]”代码对[ebp-104h]地址取一双字放入ecx寄存器中。

           由于设置成unsigned char类型,此时ch取值范围为0至255。在char版本中编译器使用“movsx”进行符号扩展来限制char的取值范围,而在unsigned char版本中编译器只是确保unsigned char类型占一字节。

        当ch=255时,

           执行“00401185   mov         ecx,dword ptr [ebp-104h]”        后ecx寄存器存储的是“0xCCCCCCFF”,

           执行“0040118B   and         ecx,0FFh”                                      后 ecx寄存器存储的是“0xFF”,判断等于MAX                                                                                                      执行循环体内赋值代码,

           执行到“00401199   mov         edx,dword ptr [ebp-104h]”   后edx寄存器存储的是“0xCCCCCCFF”,

           执行“0040119F   and         edx,0FFh”                                      后edx寄存器存储的是“0xFF”
           执行到“004011AB   mov         byte ptr [ebp+edx-100h],al” 后[ebp+edx-100h]的地址为“0x0013ff7f”


        此时[ebp-104h]处存储的是“0xFF”继续执行下一轮for循环。

           执行“00401177   mov         al,byte ptr [ebp-104h]
                      0040117D   add         al,1
                      0040117F   mov         byte ptr [ebp-104h],al”代码后,[ebp-104h]处存储数据将变为“0x00”,之后又会从ch=0开始执行for循环,程序再一次陷入死循环。


    三、正确版本

           其实,把char改为unsigned char后,还需要把for循环中的判断语句改成ch<MAX即可。正确代码如下:

    #include <iostream>
    using namespace std;
    
    #define MAX 255
    
    main()
    {
          char p[MAX+1];
          unsigned char ch;  //修改成无符号char型
          
          for (ch=0;ch<MAX;ch++)
          {
              p[ch]=ch;
              cout<<ch<<" ";
              }
    	  p[ch] = ch;
          cout<< ch<<" ";
    }

             

         【注】本文目的在于通过一个题目的深入分析,了解编译器在处理char与unsigned char的不同之处。就题目本身而言,修改方法很多,但通过本文的思维方式,可以深入到编译器层面了解陷入死循环的根本原因。此篇内容是对《程序员面试宝典(第二版)》P.208 面试例题3的深入思考。




    展开全文
  • hashmap死循环示例及检测方法

    千次阅读 2016-08-13 16:39:27
    hashmap属于线程不安全容器,在并发环境有可能发生死循环。本文将模拟死循环出现的场景,再结合jstack说明如何一步步定位出现死循环的代码。
  • python for-Python for死循环

    千次阅读 2020-11-01 12:11:56
    编写死循环程序实际上是不对的,一旦写出来一个程序运行后发现是死循环,一定要立即终止程序的运行!用Python实现一个死循环非常简单,while True就可以。for实现死循环步长为0然而我的标题是要求用Python的for实现...
  • 原理:看报错信息类DruidDataSource.java:2715,下面有一源码,在2721行处当错误次数大于connectionErrorRetryAttempts且timeBetweenConnectErrorMillis 大于0,connectionErrorRetryAttempts默认值为1,...
  • HashMap 中的死循环

    千次阅读 多人点赞 2020-07-06 10:14:29
    笔记摘录自疫苗:JAVA HASHMAP的死循环 1.存在的问题 单线程的程序使用 HashMap 没有问题,但是由于程序性能的需求,程序由单线程变为多线程,这时使用 HashMap 就可能会产生问题。 程序经常占了100%的CPU,查看...
  • HashMap进行put操作会引起死循环

    千次阅读 2020-07-03 13:22:33
    最近在磕《java并发编程艺术》,在看到第六章的时候出现了下面不是很理解的东西,如下 《java并发编程艺术》截取 为什么要使用ConcurrentHashMap 在并发编程中使用HashMap可能导致程序死循环。而使用线程安全...
  • 死循环警告⚠】i=i++导致的死循环

    千次阅读 多人点赞 2021-07-14 12:16:08
    看到下面的这代码,相信广大CRUD程序猿在亲切不过了吧?有没有发现哪里不对呢? for (int i = 0; i < Num; i = i++) { ...... } 发现错误的同学,没必要再往下看了。。。 ------------------------------...
  • 【Map】——HashMap死循环

    千次阅读 2018-12-20 10:38:32
    死循环 Hash表数据结构 简单地说一下HashMap这个经典的数据结构。 HashMap通常会用一个指针数组(假设为table[])来做分散所有的key,当一个key被加入时,会通过Hash算法通过key算出这个数组的下标i,...
  • 在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历过,本来觉得没什么好写...
  • HashMap并发导致死循环 CurrentHashMap

    千次阅读 2018-02-05 20:02:46
    原文链接:... 为何出现死循环简要说明 HashMap闭环的详细原因 ...为何出现死循环简要说明 ... HashMap是非线程安全的,在并发场景中如果不保持足够的同步,就有可能在执行HashMap.get时进入死循环,将CPU
  • 一个For语句导致死循环的例子

    千次阅读 多人点赞 2014-02-26 10:47:44
    在Java开发中常用到For循环,它对简化业务处理,提高效率,非常有...但要防止程序算法中可能导致死循环的情况,而且有的死循环还不好察觉。比如下面这个例子,算法极容易认为是50,实际上其结果是无穷大的一个死循环
  • 检测Lua脚本中死循环及解决方法

    千次阅读 2018-08-30 17:02:50
    检测Lua脚本中死循环及解决方法是本文要介绍的内容,一般LUA在测试的时候,往往会因为什么原因导致死循环,那么本文将会解决...所以检测用户脚本中的死循环并中止这脚本的运行就显得非常重要了。 可是,一个现...
  • //跳转到应用程序段 //appxaddr:用户代码起始地址. void iap_load_app(u32 appxaddr) { //(用户代码的第一个字存放的是堆栈的栈顶地址,下面即检查此地址) if(((*(vu32*)appxaddr)&0x2FFE0000)==0x...
  • Java HashMap的死循环

    万次阅读 热门讨论 2013-09-23 14:05:57
    在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历过,本来觉得没什么好写...
  • 但是,如果不用volatile来标识,会不会导致线程死循环?比如下面的伪代码: static int flag = -1; void thread1(){ while(flag > 0){ //wait or do something } } void thread2(){ //do something f
  • iOS-RunLoop充满灵性的死循环

    万次阅读 2016-09-19 08:34:10
    RunLoop字面意思是跑圈,在我们的项目中其实就是运行循环,而且是充满灵性的死循环,为什么说他充满灵性呢?因为他可以在我们需要的时候自己跑起来运行,在我们没有操作的时候就停下来休息。充分节省CPU资源,提高...
  • 下面代码要实现的功能是往整数变量i中输入一个数据,输入数字1时退出,然而当输入一个字符时,整个程序会变成一个死循环。 C++代码: int i=0; while (i!=1) { cout cin>>i;//i为整数类型,当输入一个...
  • 关于Looper.loop()死循环???

    千次阅读 2018-05-28 15:51:56
    一直以为自己把Android消息机制弄明白了,直到前时间面试,发现还有细节方面没搞清楚,查找相关资料,此篇文章是对Looper对象是怎么获取的,线程里的ThreadLocal,Looper.loop()死循环问题等的理解和总结。...
  • 对于一个简单地for语句,学过C的朋友可能觉得很简单,但是,看完下面这个看似简单程序还能想明白的朋友(实则并不简单), 那才是真的不错,,好了,不废话了,大家看代码吧!!! #include #include int main()...
  • 从集合的resize看Java HashMap的死循环

    千次阅读 2016-03-17 17:09:31
    问题的症状 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题。后来,我们的程序性能有问题,所以...但是过时间又会来。而且,这个问题在测试环境里可能很难重现。
  • 今天好蠢,期末忙于应付考试编个小程序手都生了, scanf("%d",&p->num);写成了scanf("&d",&p->num); 【当时还以为是结构体的问题呢= =】还有,scanf里的“”中间的部分并不会给你检错!!! 原因: '&d'并不是...
  • C语言_04 三种程序结构 顺序, 选择(分支), 循环结构

    万次阅读 多人点赞 2018-02-06 18:31:49
    概念 在C语言程序中,一共有三种程序...循环结构,循环结构有一个循环体,循环体里是一代码。对于循环结构来说,关键在于根据判断的结果,来决定循环体执行多少次。C语言循环控制语句是一个基于C语言的编程语句,...
  • 在开发内核模块或驱动时,如果处理失误,导致内核线程中出现死锁或者死循环,你会发现,除了重启之外,你没有任何可以做的。这时你的输入不起任何作用,终端(不是指远程的ssh工具)只会在那重复的输出类似“BUG: ...
  • 问题的症状 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题。后来,我们的程序性能有问题,...但是过时间又会来。而且,这个问题在测试环境里可能很难重现。
  • 而让人想不到的解决方案竟是下面代码 [java]   view plain copy webView.setWebViewClient( new  WebViewClient() {      @Override   ...
  • __gnu_cxx::hash_map死循环一例

    千次阅读 2010-06-23 17:44:00
    /// 一个hash_map死循环的例子: class obj { public: obj(char *_name) { strncpy(name, _name, 31); } char name[32]; /// anyothers }; hash_map*, obj*> list; typedef hash_...
  • 让QT 程序休眠一时间的方法

    万次阅读 2018-07-23 17:23:00
    在Qt程序中,我们有时候会遇到这样的需求,比如让程序暂停(休息、休眠)一时间。 最开始我需要这样的需求时候,我第一反应想到的是在QT Assistant 中搜索sleep方法,企图寻找让程序暂停、休眠一时间的方法,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 90,270
精华内容 36,108
关键字:

下面程序段不是死循环的是