main program run like an infinite while loop
Microcontrollers are often programmed bare metal , meaning your program has to initialize the CPU and RAM to get your program going. This is called a startup script and some IDEs/compilers may hide it from the user at first glance. 

The startup script does the bare minimum to get to a C main, combined with the C "environment". That is (optionally sometimes) filling RAM with zeros, and most importantly copying variables with predefined values from FLASH to RAM. E.g. if you declare a (global) variable with an initial value, it is stored in program FLASH and copied to RAM before main is called.

I suspect you use XC16 or C30 compiler. You can find these scripts in XC16/v*.**/src/libpic30.zip in the files crt0_standard.s. It contains the following (simplified for this example) start-up code:

        mov      #__SP_init,w15    ; initialize w15
        mov      #__SPLIM_init,w14


        mov      w14,_SPLIM        ; initialize SPLIM
        nop                        ; wait 1 cycle
    mov  #__enable_fixed, w0
        cp0      w0
        bra  z, CORCON_RESET 
        mov      #0x0010,w0
        mov      w0,CORCON         ; enable super saturation and clear IF

CORCON_RESET:
        rcall    __psv_init        ; initialize PSV
        mov      #__dinit_tbloffset,w0 ; w0,w1 = template
        mov      #__dinit_tblpage,w1   ;
        rcall    __data_init_standard  ; initialize data

        mov      #__has_user_init,w0
        cp0      w0                ; user init functions?
        bra      eq,1f             ; br if not
        call     __user_init       ; else call them
1:
        call  _main                ; call user's main()

        .pword 0xDA4000            ; halt the simulator
        reset                      ; reset the processor


Even if you don't speak assembler fluently you should see what is going on. The script initializes the stack, some CPU registers, initialize PSV &amp; data memory (e.g. copying pre-initialized variable contents from FLASH to RAM), and then call your main function.

The script more or less expects the main will never return, which is why you often see a while(1) at the end of any embedded program.

If it does return for some reason, it will execute the reset instruction. This reinitializes everything again and eventually call main again. This turns into the behavior you're seeing, namely it's looping.