Resources?

Shaman

New member
Joined
Sep 18, 2008
Messages
4
Programming Experience
5-10
I just converted one of my old and tiny VB6 projects into VB.NET as a personal introductory step to NET (around 50 lines of code or so). It is a little executable that uses WMI to query for various info (OS type, RAM quantity, process count, etc) and results are not pretty.

After taking care of dozen or so issues pointed out by the report generated by the migration wizard (16 to be exact on top of only 50 lines or code) I got the NET port to compile.

Issue now is that the VB.NET port uses 49296KB of RAM (as per taskmgr as of few min ago), while VB6 based app takes only 2204KB.

Is this normal NET behavior?
 
Last edited:
Issue now is that the VB.NET port uses 49296KB of RAM (as per taskmgr as of few min ago), while VB6 based app takes only 2204KB.

Is this normal NET behavior?
Yes, this was one of the most asked questions on the internet in 2002, and it is still quite popular among first time .Net users. The numbers you are seeing are loose allocations by the .Net memory management. Minimize the app and perhaps you will see 1234KB. Never mind these figures, just code well.
 
In this particular instance, there is nothing much there to code to being with. Only 47 lines of code in VB6 version, 54 in NET version. Minimizing changed nothing. It starts out at 24-25MB and rises to 55-60MB after few minutes and stays there. Minimized or not. And that's all before I even start the app. I'm just talking about the app while its sitting idle on desktop. Starting it adds another 15MB or so. (Once started it dumps all the data it gathers into a .txt file every 10 seconds.)
 
Last edited:
I just changed to Vista and can no longer see those wild "memory" numbers that XP used to report, and minimizing the app in Vista also don't change the reported numbers much. I wouldn't worry about memory usage anyway unless you think you have done something really bad memory wise in coding. If you want you can upload the project source or necessary parts to reproduce the memory display so I could have a look, it must be of a nature other people (me for instance) can be able to run it though..
 
I'm using Vista as well. Although I could boot up into XP or start my XP VM, but I don't think it would matter that much. I will test the resource consumption under XP later on.

As for the source, here is the NET port generated by the migration wizard. I had to tweak it a bit to compile.

VB.NET:
Option Strict Off
Option Explicit On
Friend Class WMISysInfo
	Inherits System.Windows.Forms.Form
	

    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByRef lParam As Int32()) As Integer
	Public totalupdates As Integer
	
	Private Sub Command1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click
		End
	End Sub
	
	Private Sub wmiProcessorInfo()
		
		Dim cpuSet As WbemScripting.SWbemObjectSet
		Dim cpu As WbemScripting.SWbemObject
		Dim cpus(10) As String
		

		cpuSet = GetObject("winmgmts:{impersonationLevel=impersonate}").InstancesOf("Win32_Processor")
		
		For	Each cpu In cpuSet
			

			cpus(0) = cpu.CurrentClockSpeed

			cpus(1) = cpu.L2CacheSize

			cpus(2) = cpu.LoadPercentage
			
			
		Next cpu
		
		Dim setSys As WbemScripting.SWbemObjectSet
		Dim sys As WbemScripting.SWbemObject
		Dim syss(10) As String
		

		setSys = GetObject("winmgmts:{impersonationLevel=impersonate}").InstancesOf("Win32_OperatingSystem")
		
		For	Each sys In setSys
			

			syss(0) = sys.TotalVisibleMemorySize

			syss(1) = sys.FreePhysicalMemory

			syss(2) = sys.TotalVirtualMemorySize

			syss(3) = sys.FreeVirtualMemory

			syss(4) = sys.OSType
			
			If CDbl(syss(4)) = 16 Then
				syss(7) = " Windows 95"
			ElseIf CDbl(syss(4)) = 17 Then 
				syss(7) = " Windows 98"
			ElseIf CDbl(syss(4)) = 18 Then 
				syss(7) = " WINNT"
			End If
			

			syss(5) = sys.Status '(SMART disk status)

            syss(6) = sys.NumberOfProcesses
			
		Next sys
		
		Dim netSys As WbemScripting.SWbemObjectSet
		Dim net As WbemScripting.SWbemObject
		Dim nets(10) As String
		

        netSys = GetObject("winmgmts:{impersonationLevel=impersonate}").InstancesOf("Win32_NetworkAdapter")
		
		For	Each net In netSys
			
		Next net
		
		FileOpen(1, Text2.Text, OpenMode.Output)
		PrintLine(1, "----------------------------------------------------------------------")
		PrintLine(1, "Server Info: (updated every " & (CDbl(Text1.Text) / 1000) & " seconds)")
		PrintLine(1, "----------------------------------------------------------------------")
		PrintLine(1, "CPU Type: " & cpus(3))
		PrintLine(1, "Current Clock Speed: " & cpus(0) & "MHz")
		PrintLine(1, "L2 Cache Size: " & cpus(1) & "KB")
		PrintLine(1, "----------------------------------------------------------------------")
		PrintLine(1, "CPU Load: " & cpus(2) & "%")
		PrintLine(1, "----------------------------------------------------------------------")
		PrintLine(1, "Total RAM: " & CShort(CDbl(syss(0)) / 1024) & " MB")
		PrintLine(1, "Free RAM: " & CShort(CDbl(syss(1)) / 1024) & " MB")
		PrintLine(1, "Total VMem: " & CShort(CDbl(syss(2)) / 1024) & " MB")
		PrintLine(1, "Available VMem: " & CShort(CDbl(syss(3)) / 1024) & " MB")
		PrintLine(1, "----------------------------------------------------------------------")
		PrintLine(1, "S.M.A.R.T. Status: " & syss(5))
		PrintLine(1, "Processes Running: " & syss(6))
		PrintLine(1, "----------------------------------------------------------------------")
		FileClose(1)
		
		Label3.Text = "Server Info: (updated every " & (CDbl(Text1.Text) / 1000) & " seconds)"
		Label4.Text = "----------------------------------------------------------------------"
		Label5.Text = "CPU Type: " & cpus(3)
		Label6.Text = "Current Clock Speed: " & cpus(0) & "MHz"
		Label7.Text = "L2 Cache Size: " & cpus(1) & "KB"
		Label8.Text = "----------------------------------------------------------------------"
		Label9.Text = "CPU Load: " & cpus(2) & "%"
		Label10.Text = "----------------------------------------------------------------------"
		Label11.Text = "Total RAM: " & CShort(CDbl(syss(0)) / 1024) & " MB"
		Label12.Text = "Free RAM: " & CShort(CDbl(syss(1)) / 1024) & " MB"
		Label13.Text = "Total VMem: " & CShort(CDbl(syss(2)) / 1024) & " MB"
		Label14.Text = "Available VMem: " & CShort(CDbl(syss(3)) / 1024) & " MB"
		Label15.Text = "----------------------------------------------------------------------"
		Label16.Text = "S.M.A.R.T. Status: " & syss(5)
		Label17.Text = "Processes Running: " & syss(6)
        Label18.Text = "----------------------------------------------------------------------"
		
	End Sub
	
	
	Private Sub Command2_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command2.Click
		If Timer1.Enabled = False Then
			Timer1.Enabled = True

            Timer1.Interval = CInt(Text1.Text)
			Command2.Text = "Pause WMISysInfo"
			Text1.Enabled = False
			Text2.Enabled = False
		ElseIf Timer1.Enabled = True Then 
			Timer1.Enabled = False
			Command2.Text = "Start WMISysInfo"
			Text1.Enabled = True
			Text2.Enabled = True

        End If
		
		
	End Sub
	
	Private Sub WMISysInfo_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load
		totalupdates = 0
	End Sub
	
	Private Sub Timer1_Tick(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Timer1.Tick
		Call wmiProcessorInfo()
		totalupdates = totalupdates + 1
	End Sub
End Class
 
When I run it starts at 14M and "stabilizes" at 28M, this is the total working set including shared memory allocations for framework itself and uncollected garbage, the private working set is much lower. I wouldn't worry about it.

What I would do is ditch COM (WbemScripting) and VB6 legacy methods and use available managed .Net functionality instead. This would be a better solution, run better with .Net platform, run faster, use less memory, and improve your .Net programming skills.

.Net has WMI support in System.Management namespace. For file IO I would use the IO.StreamWriter or similar. Never use End statement to terminate the application if you don't have a specific reason to, instead use Me.Close() method. See thread http://www.vbdotnetforums.com/articles-interest/13972-wmi-code-creator-1-0-a.html about .Net WMI resources and tools, especially note post 5 about creating strongly typed WMI classes.

Without changing anything else in form or code structure the direct translation is this:
VB.NET:
Dim cpus(10) As String
For Each cpu As Win32.Processor In Win32.Processor.GetInstances
    cpus(0) = cpu.CurrentClockSpeed
    cpus(1) = cpu.L2CacheSize
    cpus(2) = cpu.LoadPercentage
    Exit For
Next cpu

Dim syss(10) As String
Dim sys As New Win32.OperatingSystem0
syss(0) = sys.TotalVisibleMemorySize
syss(1) = sys.FreePhysicalMemory
syss(2) = sys.TotalVirtualMemorySize
syss(3) = sys.FreeVirtualMemory
syss(4) = sys.OSType

If CDbl(syss(4)) = 16 Then
    syss(7) = " Windows 95"
ElseIf CDbl(syss(4)) = 17 Then
    syss(7) = " Windows 98"
ElseIf CDbl(syss(4)) = 18 Then
    syss(7) = " WINNT"
End If

syss(5) = sys.Status '(SMART disk status)
syss(6) = sys.NumberOfProcesses

Using writer As New IO.StreamWriter(Text2.Text, False)

    writer.WriteLine("....")
    '...more file lines
End Using

'...set labels text
For generated Win32.OperatingSystem0 class I actually had to make a correction for it to work, the ConstructPath had to be changed to Return "Win32_OperatingSystem=@". Weird problem.
 
Is there any way to list what objects are in memory besides the typical dump file & stack trace?

I'm not new to .Net but the memory creep drives me up the wall. I'd love to be able to call a function that would show me for example that I have X amount of datasets, class obects exc still open.
 
I just realized that this page/thread comes up on Google search when looking for WMI/VB.net related info, and I must point out to any random passerby that JohnH's code is non-functional. Completely.

Anyways, System.Management/System.Management.Instrumentation still takes advantage of the underlying Win32 API and lot of the low-level plumbing is still COM in nature. There is no real way to truly "ditch COM (WbemScripting) and VB6 legacy methods and use available managed .Net functionality instead" as JohnH puts it, since there are no truly pure .Net native methods and/or alternatives to do it.

Since my first posting I've written several simple applications in .Net purely for exercise purposes, including a better GUI frontend for defrag in Vista. As for the original VB6 WMI application, I've rewritten that in C++ and everything is done in raw Win32 API calls. Naturally, resource footprint of that version is ridiculously low. Even when compared to VB6 version.
 
Shaman said:
I must point out to any random passerby that JohnH's code is non-functional. Completely.
Works for me. What is your problem?
the underlying Win32 API and lot of the low-level plumbing is still COM in nature.
Absolutely not. To use those APIs from COM you need a COM library like WbemScripting, which you should avoid when .Net provides a managed interface for the same. There is more to .Net than you know, and a reason MS explicitly moves away from COM tech. .Net provides a default interface to COM called "Interop", see CodeProject: Understanding Classic COM Interoperability With .NET Applications. A lot of .Net functionality is well done faultless wrappers around common Win32 APIs, for those you'd waste a lot of time and typing doing manually while the chances of doing something wrong memory or otherwise would be high. And note that all of .Net Framework class library is written in a .Net language where they call directly to Win32 functions when needed as you also can do in VB.Net and managed C++. .Net library, memory management and assembly/machine code compilers also do other optimizations that can offer benefits from native written code. Wiki has some info about COM and .Net here: Component Object Model
 
Back
Top