No announcement yet.

Is It Possible To Guarantee A Program's Running Memory Size

  • Filter
  • Time
  • Show
Clear All
new posts

  • #21

    Maybe you can find some use somewhere in this. It runs every time I start up but you will probably not want that but maybe you can check GlobalMemoryStatus or GlobalMemoryStatusEx in your program(s) and issue a warning based on them.

    '                   PBWin 8.?      - WinApi 3/07/2003                                     '
    ' Memory_Display.bas 08/15/05 by Gösta H. Lovgren 
    ' It creates a log file entry in C:\Memory_Log.txt showing processes
    #Compile Exe               
    #Dim All  ' forces all variables to be explicitly identified, 
              ' (a very good habit to get into) 
    #Include "WIN32API.INC" 'needed by all programs
    #Include ""
    #Include ""
    #Include "C:\Power Basic\Includes\"
    Declare Function Programs_Running(Srch$) As Long
    'Needed for Is_Program_Running
    Type EnumType
     hndl       As Dword
     zClass     As Asciiz * %Max_Path
     zCaption   As Asciiz * %Max_Path
     id         As Dword
     hParent    As Dword
     count      As Dword
    End Type
    Global Process_Running$()
    %Refresh_Btn = 500
    %Msg_Exit_Button_Id = 600
    %Msg_Label  = 601                                              
        'Main Callback Processor
    CallBack Function CB_Main_Processor AS LONG
        Select Case CbMsg     
            Case %WM_COMMAND  
                Select Case CbCtl 
                  Case %Refresh_Btn
                    Select Case CbCtlMsg
                    End Select
                End Select
        End Select    
    End Function                     
    '  dwLength As Dword
    '  dwMemoryLoad As Dword
    '  dwTotalPhys As Dword
    '  dwAvailPhys As Dword
    '  dwTotalPageFile As Dword
    '  dwAvailPageFile As Dword
    '  dwTotalVirtual As Dword
    '  dwAvailVirtual As Dword
    'End Type
    '  dwLength As Dword
    '  dwMemoryLoad As Dword
    '  ullTotalPhys As Quad
    '  ullAvailPhys As Quad
    '  ullTotalPageFile As Quad
    '  ullAvailPageFile As Quad
    '  ullTotalVirtual As Quad
    '  ullAvailVirtual As Quad
    '  ullAvailExtendedVirtual As Quad
    'End Type
    Sub Mem_Available
      Local m As MEMORYSTATUS
       GlobalMemoryStatus m  'fil values
       Local p$, MegaBytes&,KiloBytes&                                           
       MegaBytes = 1024 * 1024 
       KiloBytes = 1024  
       p$ = "Values on 4g installed" & $CrLf & _
            "MEMORYSTATUS yields:" & $CrLf & _
            Using$("#,### Mb Installed ", m.dwTotalPhys \ MegaBytes) & $CrLf & _
            Using$("    #% in use", m.dwMemoryLoad) & $CrLf & _
            Using$("#,### kb Available", m.dwAvailPhys \ KiloBytes) & $CrLf & _
            Using$("#,### Mb User possible", m.dwAvailVirtual \ MegaBytes) 
       Local  p2$
        p2$ = Using$("  #,### Mb Installed", m.dwTotalPhys \ MegaBytes) & _
              Using$("   ##% in use", m.dwMemoryLoad) & _
              Using$("   #,### kb Avl", m.dwAvailPhys \ KiloBytes) 
      Local m_Ex As MEMORYSTATUSEX 'get larger numbers?
      Local GMSX As Long               
      ' dwLength Member Of m_ex To SizeOf(m_ex)
      m_Ex.dwLength = SizeOf(m_ex)
      GMSX = GlobalMemoryStatusEx(m_Ex) 'get values
      Local k&, Meg&, gig&
      k = 1024
      Meg = k * k
      gig = meg * k
      Local p3$, fmt$
        fmt$ = " ###,###,# meg \                      \  "
        p3$ = $CrLf & $CrLf & "MEMORYSTATUSEX yields: " & $CrLf & _
              Using$(fmt$, m_ex.ullTotalPhys / meg, "ullTotalPhys") & $CrLf & _
              Using$(fmt$, m_ex.ullAvailPhys / meg, "ullAvailPhys") & $CrLf & _
              Using$(fmt$, m_ex.ullTotalPageFile / meg, "ullTotalPageFile") & $CrLf & _
              Using$(fmt$, m_ex.ullAvailPageFile / meg, "ullAvailPageFile") & $CrLf & _
              Using$(fmt$, m_ex.ullTotalVirtual / meg, "ullTotalVirtual") & $CrLf & _
              Using$(fmt$, m_ex.ullAvailVirtual / meg, "ullAvailVirtual") & $CrLf & _
              Using$(fmt$, m_ex.ullTotalPhys / meg, "ullAvailExtendedVirtual") 
         p$ = p$ & p3$ & $CrLf & Using$("#, Returned from GMSX", GMSX)
      Call Clipboard_Set_Text(p$)
      Local FileNum&, File_Name$
      File_Name$ = "C:\Memory_Log.txt"
      Call  Msgbox_Dialog("Memories (in " & File_Name$ & ")", p$)
    '  Kill File_Name$ :MsgBox File_Name$,, "Killed " :Exit Sub
      Local Mem_Lines&, Mem_Lin$, x&, dt$, tm$, Flag&, New_Day_Flag&   
      New_Day_Flag = 1 'assume a new day  
      dt$ = Date$
      tm$ = Time$
      FileNum = FreeFile
      Open File_Name$ For Input As #Filenum
        FileScan #FileNum, Records To Mem_Lines& 'get number of lines
         'check for same date
        For x = 1 To Mem_Lines
          Line Input #FileNum, Mem_Lin$
           If InStr(Mem_Lin$, dt$) Then 'have line with same date?
             dt$ = Space$(Len(dt$))                  
             Flag = x  
             Reset New_Day_Flag 'not a new date
             Exit For 
           End If
        Next x   
        'check for same hour
      If Flag Then
         If Mid$(Mem_Lin$, 12, 2) = Left$(tm$, 2) Then'have line with same hour?
            Mid$(tm$, 1, 4) = "   "
            For x = Flag To Mem_Lines
              Line Input #FileNum, Mem_Lin$
               If  Mid$(Mem_Lin$, 12, 2) = Left$(tm$, 2) Then 
                 Mid$(tm$, 1, 4) = "   "                  
                 Exit For 
               End If
            Next x   
         End If 
      End If  
      Close Filenum          
       Local  z$
        z$ = "Eudora"
        Flag = Programs_Running(p$)
       FileNum = FreeFile
       Open File_Name$  For Append As #FileNum 
       Print #FileNum,  " " 
       If New_Day_Flag Then
          Print #FileNum, $CrLf& $CrLf & "*******************  " & dt$ & "  *******************"
          lset dt$ = " "
       End If    
       Print #FileNum, Dt$ & " " & Tm$ & p2$
          For x = 0 To UBound(Process_Running$())
             Print #FileNum,Using$("#, ", x) & Process_Running$(x)
          Next x
       Close #FileNum
    'from WinApi Help
    'The MEMORYSTATUS structure contains information about current memory availability. The GlobalMemoryStatus Function uses this structure. 
    'typedef struct _MEMORYSTATUS { // mst  
    '    Dword dwLength;        // sizeof(MEMORYSTATUS) 
    '    Dword dwMemoryLoad;    // percent of memory in use 
    '    Dword dwTotalPhys;     // bytes of physical memory 
    '    Dword dwAvailPhys;     // free physical memory bytes 
    '    Dword dwTotalPageFile; // bytes of paging file 
    '    Dword dwAvailPageFile; // free bytes of paging file 
    '    Dword dwTotalVirtual;  // user bytes of address space 
    '    Dword dwAvailVirtual;  // free user bytes 
    'Indicates the Size Of the structure. The calling process should Set this Member prior To calling GlobalMemoryStatus. 
    'Specifies a number between 0 And 100 that gives a general idea Of current memory
    '    utilization, 
    '  In which 0 indicates no memory use And 100 indicates full memory use. 
    'Indicates the total number Of bytes Of physical memory. 
    'Indicates the number Of bytes Of physical memory available. 
    'Indicates the total number Of bytes that can be stored In the paging file. 
    '   Note that this number does Not represent the actual physical Size Of the 
    '   paging file On disk. 
    'Indicates the number Of bytes available In the paging file. 
    'Indicates the total number Of bytes that can be described In the User mode 
    '   portion Of the virtual address space Of the calling process. 
    'Indicates the number Of bytes Of unreserved And uncommitted memory 
    '  In the User mode portion Of the virtual address space Of the calling process. 
    End Sub
    ' Msgbox_Dialog(Hdr$, Msg$) starts here
    ' Just add:
    '%Msg_Exit_Button_Id = 600
    '%Msg_Label  = 601                                              
    ' and it's all set to go
    Sub Msgbox_Dialog(Hdr$, Msg$)
      Local hCaller As Dword
      Local Dialog_Height&, Dialog_Width& 
       Dialog_Height = 18 * 14 'Lines x 14 = any size you want
       Dialog_Width = 200  '   ""
       Dialog New %hWnd_Desktop, Hdr$, _
           , , _   'no values automatically centers it
           Dialog_Width&, Dialog_Height, _  'size to make it
           To hCaller      'Assign a handle
      Local bg&
       bg& =  252 + (241 * 256) + (167 * 256 * 256) 'light yellow
      Dialog Set Color hCaller,  bg, %Blue
      Local Col&, Row&, Box_Height&, Label_Height&, l$ 
         Col = 10
         Box_Height = 12 'depends on lf.lfheight below  
         Row = 1'Box_Height '* 3                   
         Label_Height& = Dialog_Height - Box_Height - 2
      Control Add Label, hCaller, %Msg_Label, Msg$, _
         Col, Row, _
         Dialog_Width - 20, Label_Height&, _
         %SS_Center Or %SS_NOTIFY
      Control Set Color hCaller, %Msg_Label, %Blue,  bg
      Local lf As LOGFONT 'LOGFONT is predefined type in WinApi32
      Local hFont As Dword
        lf.lfHeight  = Box_Height * 2 'seems to work for 6 lines
        lf.lfWidth  = 6   '3
        lf.lfFaceName = "Comic Sans MS" 
        hFont = CreateFontIndirect(lf)
        Control Send hCaller, %Msg_Label, %WM_SETFONT, hFont, 0
      Row = Dialog_Height - Box_Height           
      Local Btn_Width&
      l$ = " O&kay   "
       Btn_Width = Len(l$) * 3 'adjust depending on font size used
       Col = (Dialog_Width - Btn_Width) \ 2
    '  Control Add Button, hCaller, %Msg_Exit_Button_Id, l$, _
    '     Col, Row, _ '130
    '     Btn_Width, Box_Height&, _
    '     %BS_Left
       Dialog Show Modal hCaller  Call Msgbox_CB
    End Sub
    '  ***
    CallBack Function Msgbox_CB&     
        Select Case CbMsg 
           Case %WM_COMMAND
             Select Case CbCtl 
               Case 1 'enter
                 Dialog End CbHndl
               Case Else
                Select Case CbCtlMsg
                  Case %BN_Clicked, 1, 0 
                    Dialog End CbHndl
                End Select
             End Select ' end Cbctl
        End Select ' end CbMsg
    End Function
    ' Msgbox_Dialog(Hdr$, Msg$) ends here
    'This is adapted from code by Pierre Bellisle 
    Function Programs_Running(Srch$) As Long
     Local hProc     As Long
     Local hControl  As Long
     Local idControl As Long
     Local SomeText  As Asciiz * %Max_Path '** Pierre had it set at 50 to trap longer strings
     Local EnumTry1  As EnumType               'I changed it for "playing" purposes
     Local EnumTry2  As EnumType  
     'The dialog title that we want to find
     EnumTry1.zCaption = Srch$
     'Zero mean that we want a window under the desktop
     EnumTry1.hParent  = 0
    'If window exist EnumTry will be filled with window handle
     EnumWindows CodePtr(EnumWindowProc), VarPtr(EnumTry1)
      Srch$ = EnumTry1.zCaption
     'We got a hit so set value of function
     If EnumTry1.hndl Then
       Function = -1
     End If
    End Function
    'Retreive windows controls via class
    Function EnumControl(ByVal hWindowProc As Long, ByVal lParam As Long) As Long
     Local LenClass    As Long
     Local LenCaption  As Long
     Local zClass      As Asciiz * %Max_Path
     Local zCaption    As Asciiz * %Max_Path
     Local EnumTryPtr  As EnumType Pointer
     Static Counter    As Long
     'Retreive a pointer to EnumTry2 so we can read and change it
     EnumTryPtr = lParam
     'Get the class of the control
     LenClass = GetClassName(hWindowProc, zClass, %MAX_PATH)
        '** GetClassName is an API function 
          'hWindowProc has been determined by the call to ... 
            '.. well I don't know where it has been assigned unless it was with the
            'call to EnumChildWindows above
          'zClass must be returned by GetClassName  
          '%Max_Path is a constant of 256, presumably tells GetClassName not to search 
            'more than is necessary?
     'Get the text of the control
    ' SendMessage hWindowProc, %WM_GETTEXT, %Max_Path, VarPtr(zCaption)
          '**  SendMessage is an API call 
          '** %Wm_GetText is telling SendMessage what to do.
          '** %Max_Path is how many bytes to do it for  
          '** VarPtr is telling SendMessage where to put the text found
          '   so it can be read in zCaption 
     'Did we found our control class?
     If UCase$(zClass) = UCase$(@EnumTryPtr.zClass) Then
       Incr Counter  'We want the third Edit control
       If Counter = @EnumTryPtr.Count Then 'Found the "Interface Prefix" text box
         @EnumTryPtr.hndl     = hWindowProc               'Put handle  in EnumTry2
         @EnumTryPtr.zCaption = zCaption                  'Put caption in EnumTry2
         @EnumTryPtr.zClass   = zClass                    'Put class   in EnumTry2       = GetDlgCtrlID(hWindowProc) 'Get the control id and put it EnumTry2
         Function = 0 : Exit Function 'Stop enumeration and exit
       End If
     End If
     Function = 1 'True, so Function will recall itself until last window found
                     '** Now this is new to me. I was unaware a 
                     '"Function = 1 (%True)" would cause recursion
                     ' And presumably a "Function = 0 (%false)" would cause an exit
                     ' I had seen the Function = 0 in lots of code but until
                     ' now didn't know why.
    End Function
    'Retreive windows handle via caption
    Function EnumWindowProc(ByVal hWindowProc As Long, ByVal lParam As Long) As Long
     Local zCaption    As Asciiz * %Max_Path
     Local zClass      As Asciiz * %Max_Path
     Local EnumTryPtr  As EnumType Pointer
     Local LenClass    As Long
     Local LenCaption  As Long
     'Retrive a pointer to EnumTry so we can read and change it
     EnumTryPtr = lParam
     If IsWindowVisible(hWindowProc) Then                               'Get only visible windows
       If GetParent(hWindowProc) = @EnumTryPtr.hParent Then             'Under desktop if 0 or under parent
         If IsWindowEnabled(hWindowProc) Then                           'Get only enabled windows
           LenClass   = GetClassName (hWindowProc, zClass, %MAX_PATH)   'Get the class of the dialog
           LenCaption = GetWindowText(hWindowProc, zCaption, %MAX_PATH) 'Get the caption of the dialog
            Local ll&          
              ll = UBound(Process_Running$()) + 1
           ReDim Preserve Process_Running$(ll)
            Process_Running$(ll) = zClass & " = " & _
    '         MsgBox  Process_Running$(ll),, "process"   
           'Did we found a dialog with our text?
    ' 1      If UCase$(zCaption) = UCase$(@EnumTryPtr.zCaption) Then
    ' 2      If InStr(UCase$(zCaption), UCase$(@EnumTryPtr.zCaption)) Then
    '   Must use Left$ code case 1 must be an EXACT match 
    '                       case 2 matches anytime Srch$ is in title 
           Local l&
           l = Len((@EnumTryPtr.zCaption))
           If Left$(UCase$(zCaption), l) = Left$(UCase$(@EnumTryPtr.zCaption), l) Then
             @EnumTryPtr.hndl     = hWindowProc          'Put handle  in EnumTry1
             @EnumTryPtr.zCaption = zCaption             'Put caption in EnumTry1
             @EnumTryPtr.zClass   = zClass               'Put class   in EnumTry1
             Function = 0 : Exit Function 'Stop enumeration and exit
          End If
         End If
       End If
     End If
     Function = 1 'True, so Function will recall itself until last window found
    End Function
    ' keep code above to Sub Is_This_Program_Running intact  
    '                                                                     ¤
    ' PB MAIN Start Here                                                  '
    '                                                                     ¤
    Function PBMain () As Long
       Call Mem_Available
    End Function                     
    and here's yesterday's log for example:

    ******************* 02-14-2008 *******************
    08:43:20 2,047 Mb Installed 10% in use 2,097,151 kb Avl
    0 Shell_TrayWnd =
    1 Progman = Program Manager

    12:12:07 2,047 Mb Installed 10% in use 2,097,151 kb Avl
    0 Shell_TrayWnd =
    1 EXPLOPLUSCLASS = C:\A_Original\The Lovgrens\*.* - ExplorerPlus
    2 #32770 = ExplorerPlus FTP Transfer
    3 #32770 = Trend Micro PC-cillin Internet Security 14
    4 EudoraMainWindow = Eudora - [In]
    5 SlimBrowser MainFrameW = SlimBrowser - Swede's Dock - Pictures of Lavallette, NJ
    6 TEFO_FrmNotepad = NoteTab Pro - C:\A_Original\The Lovgrens\10Trenton\index.html
    7 TApplication = NoteTab Pro - C:\A_Original\The Lovgrens\10Trenton\index.html
    8 Progman = Program Manager

    14:18:52 2,047 Mb Installed 10% in use 2,097,151 kb Avl
    0 #32770 = Windows Task Manager
    1 Shell_TrayWnd =
    2 LogoffMonitorThread_193 =
    3 LogoffMonitorThread_176 =
    4 LogoffMonitorThread_164 =
    5 LogoffMonitorThread_149 =
    6 LogoffMonitorThread_85 =
    7 LogoffMonitorThread_71 =
    8 LogoffMonitorThread_57 =
    9 LogoffMonitorThread_51 =
    10 #32770 = GoToAssist
    11 GoToAssistCustomerUIWindow =
    12 SlimBrowser MainFrameW = SlimBrowser - GoToAssist: connected
    13 Progman = Program Manager

    22:00:54 2,047 Mb Installed 10% in use 2,097,151 kb Avl
    0 Shell_TrayWnd =
    1 EXPLOPLUSCLASS = C:\*.* - ExplorerPlus
    2 Progman = Program Manager
    It's a pretty day. I hope you enjoy it.


    JWAM: (Quit Smoking):
    LDN - A Miracle Drug:


    • #22
      Clipboard Include

      And here's the clipboard Include JIC ssomeone wants to run the above:

      '<== Start of Clipboard as an Include ==>
      'Clipboard stuff gotten from Poffs but I forget from whom
      'Note t$ must be initialized - Local t$
      Function Clipboard_Set_Text Alias "Clipboard_Set_Text" _
                    (ByVal sText As String) Export As Long
        Local hData As Long, hGlob As Long
      ' ** Create a global memory object and copy the data into it
        hData = GlobalAlloc(%GMEM_MOVEABLE Or %GMEM_DDESHARE, Len(sText) + 1)
        hGlob = GlobalLock(hData)
        Poke$ hGlob, sText + Chr$(0)
        GlobalUnlock hData
      ' ** Open the clipboard
        If IsFalse(OpenClipboard(%Null)) Then
          GlobalFree hData
          Exit Function
        End If
      ' ** Paste the data into the clipboard
        EmptyClipboard  'WinAPI
        Function = SetClipboardData(%CF_TEXT, hData) 'WinAPI
        CloseClipboard  'WinAPI
      End Function
      Function Clipboard_Get_Text Alias "Clipboard_Get_Text"() Export As String
          Local zPtr As Asciiz Ptr
          OpenClipboard 0 'WinAPI
          zPtr = GetClipboardData(%CF_TEXT)
          If zPtr <> 0 Then Function = @zPtr
          CloseClipboard   'WinAPI
      End Function
      Macro Get_Clipboard =  t$ = Clipboard_Get_Text 'put cb in tb at program start 
      Macro Set_Clipboard = Clipboard_Set_Text(t$)
      '<== End of Clipboard as an Include ==>
      It's a pretty day. I hope you enjoy it.


      JWAM: (Quit Smoking):
      LDN - A Miracle Drug:


      • #23
        still pondering the situation over

        saw a program written the other day by the new vendor bust because of not enough memory, but the program was only a 16bit program.

        Well, 16-bit MS-DOS has a (1 Mb) hard limit (260 reserved for system, getting the familiar "640K" number), and 16-bit Windows a hard limit of 20 Mb (I think; maybe it's 24 Mb), and in the latter case that's system-wide.

        32-bit windows gives you -per process - the lesser of 2 GB or (Installed RAM + disk space available for use as the page (swap) file).

        AS Mr. Lofgren pointed out, GlobalMemoryStatus can tell you how much virtual memory is will be available to your process...(dwTotalVirtual member of MEMORYSTATUS structure) .. and you can decide what to do. Bear in mind that this number may change during your program run (some other process may grab lots of memory, reducing the disk space available, reducing what is available to you) ... unless you "suck it up now" by allocating that much memory. (VirtualAlloc can do this for you).

        What are you trying to do which you think might bust the (normal) 2 GB bank?

        Or for that matter, do you have to contend with some kind of 'supervisor' program which limits how much memory your process may allocate (see my link for the whole story)?

        I think we are down to requiring more info about the application to provide useful suggestions

        Or spend the relatively few dollars required to get a disk which will be "plenty." eg my home system uses 2-80 Gb FDDs, (peanuts next to some of my clients' systems where they have literally several hundred GB available). Since I put all my application data on "D:" and only program files on "C:", my free space on "C:" is typically 50-60 Gb... or will support 25 or 30 separate simultaneous processes each using "the max." (That would be a lot of memory-intensive processes).

        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]


        • #24
          I have started working on a program to monitor memory and report warning and cautions of low memory. I have some ideas that may work out well and may not. My biggest problem is programming the gui as a newbie on gui and displaying meaningful info to a user if the memory is low or becomes low.

          I just started using the globalmemorystatus function and getting use to what it actually gives me.

          It will take some time to put together a display design that the user will be comfortable with also and one that makes the user act accordingly.

          So far, i have where the program reads a command line for variables to be set. Just a few below

          display startup hidden/show
          display always on top
          display always show
          low memory setting warning
          any amount over low memory allowances
          major warning of low memory warning
          warning of memory where there is not an x amount at memory monitor startup
          location of where the program starts up on screen
          startup font size and window size
          change the default caption used to allow it easier to kill the program

          I would like to have the ability of a second program being able to execute the memory monitor program and kill the program at will.

          Thanks for all the help

          p purvis


          • #25
            Applications can use memory resource notification events to scale their memory usage as appropriate. If available memory is low, the application can reduce its working set. If available memory is high, the application can allocate more memory.

            Windows NT/2000/XP: Included in Windows XP and Windows .NET Server.
            Windows 95/98/Me: Unsupported

               hNotify = CreateMemoryResourceNotification(%LOWMEMORYRESOURCENOTIFICATION )
               [b] AND/OR [/b] 

            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]