Announcement

Collapse
No announcement yet.

What are Stack and Heap ?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Steve Hutchesson
    replied
    I take your point but you must have some give in both directions. The Mona Lisa would not have become famous if it was done with a thumbnail dipped in tar but likewise a amateur with a pallette and the brushes and paint of a master will still mess it up. Another factor is most of the old masters made their own tools, something that an amateur would not know how to do.

    Leave a comment:


  • Michael Mattias
    replied
    don't have any particular bias, line numbered code works, pure HEX works, intrinsic basic works, asm works and APIs work, the only factor I see as important is if the end results works.
    Have you forgotten so soon? It's not the paintbrush, it's the artist!

    Leave a comment:


  • Steve Hutchesson
    replied
    I am more inclined to respect the asker of the original question, you may not need the "zen" of electron flow to understand what a computer is inclined to do but some like to know how things work. PB does do all of those things #STACK settings, can allocate memory from the system that some call the "heap". The field of computing is so wide that no-one know it all and most just pick what they are interested in and as programmers, write what they need.

    I don't have any particular bias, line numbered code works, pure HEX works, intrinsic basic works, asm works and APIs work, the only factor I see as important is if the end results works.

    Leave a comment:


  • Michael Mattias
    replied
    And just in general.. ..

    Not needing to be concerned with detail management of the stack and the heap is why you paid good money for a compiler license.

    Leave a comment:


  • Steve Hutchesson
    replied
    One more try. A short demo on what the stack is doing via the two registers used in construction procedures (subs and functions in basic).
    Code:
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
        #include "\basic\include\win32api.inc"
    
        GLOBAL rESP as DWORD
        GLOBAL rEBP as DWORD
    
        MACRO showstack(UserString)
          ! mov rESP, esp
          ! mov rEBP, ebp
          StdOut "  esp = "+format$(rESP)+" ebp = "+format$(rEBP)+" "+UserString+$CRLF
        END MACRO
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    FUNCTION PBmain as LONG
    
        LOCAL cnt as DWORD
    
        showstack("stack at App entry")
    
        ! call nops                             ' call an empty FASTPROC
    
        showstack("stack at FASTPROC exit")
    
        cnt = numz                              ' call a basic function
    
        showstack("Balanced stack on FUNCTION exit")
    
        waitkey$
    
    End FUNCTION
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    FUNCTION numz() as DWORD
    
        LOCAL x1 as DWORD
        LOCAL x2 as DWORD
        LOCAL x3 as DWORD
        LOCAL x4 as DWORD
    
        showstack("FUNCTION entry")
    
        x1 = 1
        x2 = 2
        x3 = 3
        x4 = 4
    
        showstack("FUNCTION exit")
    
        FUNCTION = x1 + x2 + x3 + x4
    
    End FUNCTION
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    FASTPROC nops
    
        showstack("FASTPROC entry - ESP 4 bytes lower than caller due to CALL")
    
        ! nop
        ! nop
        ! nop
        ! nop
        ! nop
        ! nop
        ! nop
        ! nop
    
        showstack("FASTPROC exit")
    
        ! ret
    
    END FASTPROC
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    It display results like this.
    Code:
      esp = 1703444 ebp = 1703600 stack at App entry
    
      esp = 1703440 ebp = 1703600 FASTPROC entry - ESP 4 bytes lower than caller due to CALL
    
      esp = 1703440 ebp = 1703600 FASTPROC exit
    
      esp = 1703444 ebp = 1703600 stack at FASTPROC exit
    
      esp = 1703268 ebp = 1703436 FUNCTION entry
    
      esp = 1703268 ebp = 1703436 FUNCTION exit
    
      esp = 1703444 ebp = 1703600 Balanced stack on FUNCTION exit

    Leave a comment:


  • Dale Yarker
    replied
    Not only Irrelevant.
    '
    Code:
    #compile exe
    #dim all
    
    function pbmain () as long
      local MyStr as string
      local spMyStr, vpMyStr, x as dword
      MyStr = "blah, blah, brown fox ... "
      spMyStr = strptr(MyStr)
      vpMyStr = varptr(MyStr)
      x = peek(dword, vpMyStr)
      ? str$(spMyStr) + $crlf + _
        str$(vpMyStr) + $crlf + _
        str$(x)
    end function '
    When I run this spMyStr and x are the same.

    "... after the last time the string was changed." is true.
    Last edited by Dale Yarker; 25 Jul 2020, 06:48 PM.

    Leave a comment:


  • Tim Lakinir
    replied
    Thank you Everyone, learn much from here

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Michael Mattias View Post
    Make a change to the string's length and see if "24" is still true. Heck, see if any number remains true.

    The only way you can get the value of the pointer to a dynamic string's string data is to use the STRPTR function after the last time the string was changed.
    Irrelevant

    Leave a comment:


  • Michael Mattias
    replied
    Make a change to the string's length and see if "24" is still true. Heck, see if any number remains true.

    The only way you can get the value of the pointer to a dynamic string's string data is to use the STRPTR function after the last time the string was changed.

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Stuart McLachlan View Post
    All multiples of 24, that make sense.

    But logically two variables initialised with a single character one after the other with nothing happening prior to or between the assignments should be in consecutive memory blocks.
    Doh! I wasn't thinking it through.
    The pointer addresses are Virtual addresses, not memory locations.

    (MCM is the only poster so far who has actually drawn attention to the difference between virtual addresses and memory locations)

    Leave a comment:


  • Paul Dixon
    replied
    PS If you want to know where the stack pointer is pointing, you can get it like this:


    LOCAL StackPointer AS LONG

    !mov StackPointer,ESP

    Leave a comment:


  • Paul Dixon
    replied
    LOCAL variables are allocated on the stack.
    BUT dynamic string variables come in 2 parts.

    The variable itself is on the stack and contains a pointer to the string data. You get this value with VARPTR().
    The string data location is allocated by the OS and is not on the stack. You get this value with STRPTR() and it can change when the string data is changed.

    It's the same as allocating pointers.
    A LOCAL pointer will be on the stack and will be 32 bits but the data it points to could be anywhere and any size.

    The local STRING data is just a pointer and is 4 bytes long so successively declared local STRINGs will usually have addresses differing by 4 and will be located on the stack.
    These point to the content of the string and the string length but it's up to the OS to allocate that and it can vary in size and location and you just have to accept what the OS returns.

    Leave a comment:


  • Steve Hutchesson
    replied
    The terms stack and heap are wider than any particular programming language dialect. In Win32 the stack is defined in the executable file format and is usually 1 meg by default. At the programmer level the stack is memory where you pass arguments to and allocate local variables within a procedure. As part of the OS definition you have a few options, a procedure with a stackframe or without a stack frame and this is controlled by 1 or 2 registers, EBP and ESP, respectively the base pointer and the stack pointer. Depending on if you use a stackframe or not, when a procedure makes a CALL to another it pushes the return address onto the stack, literally stack memory, pushes argument after that and if LOCAL variables are required, it shifts the stack pointer ESP or with a stack frame EBP to make room for the LOCAL variables.

    On exit from a procedure, the stack must be balanced so you have a RET followed by the byte count of the arguments so the stack pointer is returned back to where it was when the procedure was called. This is why LOCAL variables only have scope while the procedure is running, the stack space is overwritten on exit and the variables no longer exist. Normally a LOCAL variable is uninitialised at entry as its contents are junk left on the stack and some languages (PB included) initialise the LOCAL variables to 0 fill (the number, not the character) at startup. You have the option in PB for advanced code to use a FASTPROC which has no stack frame unless you want to write one.

    System memory, what Stuart is calling the "heap" is a different animal, its a pool of memory that is allocated by the OS on demand with a number of system API functions, HeapAlloc(), GlobalAlloc(), VirtualAlloc() and in the case of basic string memory, SysAllocStringByteLen() which is an OLE format that works like an old PASCAL string where you have the length of the string stored in the first 4 bytes and the string data stored directly after it. While it is hidden from the basic programmer, the basic string engine handles all of the allocation and freeing of basic string memory but it is allocated memory which must be allocated and freed.

    That is the distinction between STACK and HEAP as the question was originally asked, to the programmer, stack memory is transient and automatically made available where system memory must be allocated and freed. In basic at close range, LOCAL and GLOBAL will do the same thing, you can write data to an from such variables, its just that they are created differently with different scope.

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Dave Biggs View Post
    FWIW I see the same as Rod on Win10 64bit and the same as Stuart on Win7 64bit
    Ah-ha. I'm on Win7. So it looks like Win version not "bitness" that makes the difference.

    Leave a comment:


  • Dave Biggs
    replied
    FWIW I see the same as Rod on Win10 64bit and the same as Stuart on Win7 64bit

    Leave a comment:


  • Rodney Hicks
    replied
    Multiple compilations of the code. I've no idea why it is done this way. Maybe if it has almost all program memory tied up it might change its ways, but I doubt it.

    Leave a comment:


  • Dean Gwilliam
    replied
    what a great question and answers!

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Rodney Hicks View Post
    FWIW my results for 10 runs of the code in posts 14 and 15:
    144, 168, 48, 24, 120, -120, 96, -144, 96, 48
    Win 10 32 bit
    All multiples of 24, that make sense.

    But logically two variables initialised with a single character one after the other with nothing happening prior to or between the assignments should be in consecutive memory blocks. The interesting question is why the numbers different from run to run. (From this small sample of 3 an initial hypothesis is that it is happening on 32bit windows but not on 64bit). Are the intermediate blocks of 24 bytes being used or is the behind the scenes memory allocation doing something else?

    Are these varying numbers the result of multiple runs with the same compiled application or with multiple compilations?

    Leave a comment:


  • Rodney Hicks
    replied
    FWIW my results for 10 runs of the code in posts 14 and 15:
    144, 168, 48, 24, 120, -120, 96, -144, 96, 48
    Win 10 32 bit

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Mike Doty View Post
    I'm using 32-bit Windows 10 if that makes a difference.
    Code:
    FUNCTION PBMAIN () AS LONG
    LOCAL s1,s2 AS STRING
    LOCAL p1,p2 AS LONG
    s1 = "a"
    s2 = "b"
    s1 = STRPTR(s1)
    p2 = STRPTR(s2)
    ? USING$("#",p2-p1)
    END FUNCTION
    That may well make a difference, I'm using 64 bit. But as I said before, both Local so it's not proving much.

    Leave a comment:

Working...
X