How to free memory?

New to FreeBASIC? Post your questions here.
Post Reply
zcbenz
Posts: 48
Joined: Jan 30, 2008 3:00

How to free memory?

Post by zcbenz »

In the example below ,every time the "mTray" menu popups, the memory it used would gain from 1664kb to 2192kb ,and then it would stay the 2192kb forever ,even I didn't right click on the tray icon any more.

How could I get the used 530kb memory back?

Code: Select all

#include once "windows.bi"
#include once "win\shellapi.bi"
#include once "win\tlhelp32.bi"

Declare Function WinMain ( Byval hInstance As HINSTANCE, Byval hPrevInstance As HINSTANCE,szCmdLine As String, Byval iCmdShow As Integer ) As Integer

Const WM_SHELLNOTIFY = WM_USER + 5
Const ID_EXIT =1, ID_NONE =2, ID_FREE=3

Dim Shared iTray As NOTIFYICONDATA
Dim Shared mTray As HANDLE
Dim Shared szAppName As String
Dim Shared TB_CREATED As Integer
Dim Shared MainMenu As HANDLE

End WinMain( GetModuleHandle( null ), null, Command$, SW_NORMAL )

Function WndProc ( Byval hWnd As HWND, Byval message As UINT, Byval wParam As WPARAM, _
                Byval lParam As LPARAM ) As LRESULT

  Static pt As Point
  Function = 0

  Select Case (message)
  Case WM_CREATE
          TB_CREATED = RegisterWindowMessage ("TaskbarCreated")
          Exit Function

  Case WM_DESTROY
          UnregisterClass (szAppName, GetModuleHandle( null ))
          Shell_NotifyIcon (NIM_DELETE, @iTray)
          PostQuitMessage( 0 )
          Exit Function

  Case WM_COMMAND
          Select Case LOWORD (wParam)
 			 	Case ID_EXIT
          		DestroyWindow (hWnd)
          	Case ID_NONE 
          		'
          	Case ID_FREE
          		'
          End Select 

  Case WM_CREATE
          TB_CREATED = RegisterWindowMessage ("TaskbarCreated")

  Case WM_SHELLNOTIFY
       If lParam = WM_RBUTTONDOWN Then
       	mTray = CreateMenu ()
         MainMenu = CreateMenu ()
         InsertMenu (MainMenu, 0, MF_POPUP, mTray, "invisible menu")
         
         InsertMenu (mTray, 0, MF_SEPARATOR, -1, "")
         InsertMenu (mTray, 1, MF_STRING, ID_EXIT, "E&xit")

         GetCursorPos (@pt)
         SetForegroundWindow (hWnd)
         TrackPopupMenuEx (mTray, TPM_LEFTALIGN Or TPM_RIGHTBUTTON, pt.x, pt.y, hWnd, NULL)
         PostMessage (hWnd, WM_NULL, 0, 0)
         DestroyMenu (MainMenu)
              
       EndIf 
         
  Case TB_CREATED
          Shell_NotifyIcon (NIM_ADD, @iTray)
  End Select

  Function = DefWindowProc( hWnd, message, wParam, lParam )
End Function

Function WinMain ( Byval hInstance As HINSTANCE, _
                Byval hPrevInstance As HINSTANCE, _
                szCmdLine As String, _
                Byval iCmdShow As Integer ) As Integer

        Dim wMsg As MSG
        Dim wcls As WNDCLASS
        Dim hWnd As HWND

        Function = 0

        szAppName = "Auto Servicer"

    hWnd=FindWindow(szAppName,NULL)
    If hWnd <> 0 Then
        SetForegroundWindow(hWnd)
        Exit Function
    End If

        With wcls
                .style = CS_HREDRAW Or CS_VREDRAW
                .lpfnWndProc = @WndProc
                .cbClsExtra = 0
                .cbWndExtra = 0
                .hInstance  = hInstance
                .hIcon = LoadIcon( NULL, IDI_APPLICATION )
                .hCursor = LoadCursor( NULL, IDC_ARROW )
                .hbrBackground = GetStockObject( WHITE_BRUSH )
                .lpszMenuName = NULL
                .lpszClassName = Strptr( szAppName )
        End With

        If( RegisterClass( @wcls ) = FALSE ) Then
                MessageBox( null, "This program requires Windows NT!", szAppName, MB_ICONERROR )
                Exit Function
        End If

        '' Create the window and _BUT DONT_ show it
        hWnd = CreateWindowEx( 0, szAppName, "", _
        0, _
        0, 0, 0, 0, _
                NULL, NULL, _
                hInstance, _
                NULL )
                
        'Create Tray
        iTray.cbSize = sizeof (NOTIFYICONDATA)
        iTray.hWnd = hWnd
        'iTray.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (CLOCKICON))
        iTray.uFlags = NIF_TIP Or NIF_ICON Or NIF_MESSAGE Or NIF_INFO Or NIF_STATE
        iTray.uCallbackMessage = WM_SHELLNOTIFY
        iTray.szTip= szAppName
        Shell_NotifyIcon (NIM_ADD, @iTray)

        
        While( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )
                TranslateMessage( @wMsg )
                DispatchMessage( @wMsg )
        Wend
        Function = wMsg.wParam
End Function
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Post by D.J.Peters »

Do you mean the memory from hidden window?

Joshy
zcbenz
Posts: 48
Joined: Jan 30, 2008 3:00

Post by zcbenz »

Maybe , I don't exactly know which part uses the memory.

The same thing has happened for many times.For example,after using SoundPlay function ,the memory my programme used would add about 890kb. Everytime I called a new API function, the memory usage would gain a great deal. What I want to do is to free the used memory after having used an API function.

Sorry for my bad English.
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Post by MichaelW »

Why does your WndProc select case contain two instances of case WM_CREATE? And why are you creating the menu in the WM_SHELLNOTIFY handler instead of in the WM_CREATE handler? The WM_CREATE message is sent only once, where the WM_SHELLNOTIFY message is sent repeatedly.
zcbenz
Posts: 48
Joined: Jan 30, 2008 3:00

Post by zcbenz »

I need to refresh some information of the menu when it shows, so I create the menu under WM_SHELLNOTIFY handler.And the two WM_CREATE was just my mistake.

Here is the original code :http://t6l3iw.bay.livefilestore.com/y1p ... p?download

As you see,the memory it used gained a lot when the menu shows or the Playsound works.

Thanks for your help.
voodooattack
Posts: 605
Joined: Feb 18, 2006 13:30
Location: Alexandria / Egypt
Contact:

Post by voodooattack »

Here's something I've used for an old framework called FBServ, I basically noticed the same problem, and as FBServ was built to create light-weight NT Services using FB, so I wrote this function to solve the problem:

Code: Select all

    Function SrvFlushPhysicalMem() As Integer
        
        SetLastError(NO_ERROR)
        
        Dim hProc   as HANDLE
        Dim dwMin   as UInteger
        Dim dwMax   as UInteger
        Dim ret     as Integer
        
        'Flush the process memory into the page file..
        
        'Obtain a handle for the current process
        hProc = OpenProcess(PROCESS_SET_QUOTA OR PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId())
        
        If hProc = INVALID_HANDLE_VALUE Then 
            'Couldn't open a handle to the current process..
            'Just abort.. 
            ret = FALSE
        Else
            'Get the current working set size..
            If GetProcessWorkingSetSize(hProc, @dwMin, @dwMax) = FALSE Then
                'Could not get the current values, assume defaults
                dwMin = 204800  'default (~ 400KB)
                dwMax = 1413120 'default (~ 2MB)
            End If
            
            'Flush the process' physical memory..
            If SetProcessWorkingSetSize(hProc, cuint(-1), cuint(-1)) = FALSE Then        
                ret = FALSE
            Else
                ret = TRUE
            End If
            
            'Restore old values..
            If SetProcessWorkingSetSize(hProc, dwMin, dwMax) = FALSE Then        
                ret = FALSE
            End If
            
            'Close the handle
            CloseHandle(hProc)
        End If
        
        SetLastError(NO_ERROR)
        
        Return ret
        
    End Function
What it does is simply flush most of the pages in your program's virtual memory everytime it's called, then they'll be pulled out from the pagefile through the memory manager once needed.. helps keeping your apps to a small memory footprint, in exchange for (somewhat) slower memory access :)

can be a life saver if you don't overuse it..
Post Reply