Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call Codebase from .net #5

Open
fran-gb opened this issue Sep 24, 2019 · 16 comments
Open

Call Codebase from .net #5

fran-gb opened this issue Sep 24, 2019 · 16 comments

Comments

@fran-gb
Copy link

fran-gb commented Sep 24, 2019

I am looking for examples where CodeBase is called from VB.NET or the vb6 file codebase.bas adapted for VB.NET. It exists?

I have doubts of how convert the types of parameter "as any" from vb6 to vb.net.

If someone have samples calling CODEBASE from c# its also wellcome.

@stephen144
Copy link

Today is your lucky day. Checkout this PR: #1

@fran-gb
Copy link
Author

fran-gb commented Sep 26, 2019

Today is your lucky day. Checkout this PR: #1

Thank you, but this info is specific for vb6.

But I've solved it. The parameter defined in VB6 as "as any" and not exists in VB.net can be modified in most cases "as byte()" or "as integer". Until now, I've not found any problem i a few samples that I've tried.

@trevster344
Copy link
Contributor

If you need any further examples or assistance, I develop primarily in VB.NET using Codebase.

@RicardoJarree
Copy link

@trevster344 @stephen144 have either of you had any issues with memory leaks when accessing large tables from a .NET Application? When we get the data from a DBF it will assign RAM to the application and never let go, in most cases we end up with GB's of unmanaged memory and my only thought is that the codebase library is holding onto the RAM?

Any guesses?

@trevster344
Copy link
Contributor

trevster344 commented Jun 23, 2020

@RicardoJarree Are you using read/write optimizations? The only time I have ever had memory leaks with CodeBase was when I wasn't properly disposing of my CodeBase instances in .NET via Dispose() and Finalizer(). I wrote a class that implements IDisposable and just inherit from it when I need to access CodeBase in a class. I have a few classes I wrote that do most of my CodeBase work so I don't have any more memory leaks. All of the classes that implement my disposal class use the Using Statement.

@RicardoJarree
Copy link

@trevster344 thanks for coming back to me. At the moment we access the Data4 datafile object directly. We have a method to controls opening a connection to codebase using the Code4 class and closing either datafiles or the entire codebase connection, and we ensure that we use that. We don't have a class that inherits IDisposable, would you be able to share an example?

@trevster344
Copy link
Contributor

trevster344 commented Jun 23, 2020

@RicardoJarree Here is a simple example.

`
Public MustInherit Class CodebaseDisposal
Implements IDisposable

    ''' <summary>
    ''' Flag
    ''' </summary>
    Private Init As Boolean = False

    ''' <summary>
    ''' Flag
    ''' </summary>
    Private _Shutdown As Boolean = False

    ''' <summary>
    ''' Primary codebase instance
    ''' </summary>
    Private _PrimaryCB As Long = 0

    ''' <summary>
    ''' Primary codebase instance for this container
    ''' </summary>
    ''' <returns></returns>
    Public Property PrimaryCB As Long
        Get
            If Not Init Then
                ' Only create an instance once
                Databases.ActivateCodebase(_PrimaryCB) ' Calls code4init
                Init = True
            End If
            Return _PrimaryCB
        End Get
        Set(value As Long)
            _PrimaryCB = value
            Init = True
        End Set
    End Property

#Region "IDisposable Support"
    Private disposedValue As Boolean

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If disposedValue Then Exit Sub
        If disposing Then
            ' TODO: dispose managed state (managed objects).
            GC.SuppressFinalize(Me)
        End If

        ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
        If Me._PrimaryCB > 0 AndAlso Not _Shutdown Then
            DeactivateCodebase(_PrimaryCB) ' Calls code4initundo
            _Shutdown = True
        End If

        disposedValue = True
    End Sub

    Protected Overrides Sub Finalize()
        Try
            Dispose(False)
        Finally
            MyBase.Finalize()
        End Try
    End Sub

    Public Overridable Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
    End Sub
#End Region

End Class`

A large part of this is auto-generated when you implement IDisposable but what is worth noting is the position of the clean-up operations and the usage of Finalizer(). Finalizer is what actually allows the clean-up of unmanaged resources like CodeBase, without it the Garbage Collector will not call Dispose() so if you don't use the Using Statement the garbage collector will be able to take care of your unmanaged resource(CodeBase).

This only matters if you are calling code4init more than once. If you are not then double check read/write optimization code4optimize.

@RicardoJarree
Copy link

@trevster344 thanks for that, I think the main difference which is probably causing the issue is that we are persisting codebase without disposal, whereas you are creating it each time you need it. Thanks again for the advice!

@trevster344
Copy link
Contributor

trevster344 commented Jun 23, 2020

@RicardoJarree If this is a persistent application like a desktop app and the databases are local I would recommend running an instance of CodeBase only as long as you need but it should be otherwise okay to have a long running instance.

The documentation does state to use u4Free for some cases:
This function frees memory previously allocated by other CodeBase functions such as d4fieldInfo. memPtr should point to memory allocated with one of these functions.

Pretty much everything else will be cleaned up by a simple code4initUndo. If nothing here makes sense I would recommend running a memory profiler to make sure it isn't something managed that is leaking. My solutions are mostly for ASP.NET applications because every request is a separate session.

Strings are a pretty common gotcha. Anything string over 85k in memory(large object) gets thrown into the higher heaps which are not GC'd as often as you would want.

@RicardoJarree
Copy link

@trevster344 this is basically an internal WCF webservice and then we have a task which will request and send data to and from the service on a regular basis. It's always running so the RAM creeping up is a major issue.

Had a look in our Codebase.cs file and found u4freeDefault and this is part of the Error4 class but not public. Not sure if you are using the same class to interop with the c4dll library. Nothing stopping me from adding an interop to that method I suppose though.

Running code4initUndo doesn't do anything to help the RAM usage, I've run multiple memory profilers and they all say that the leak is within unmanaged memory. Only around 200kb managed and the rest is unmanaged, anywhere up to 4gb until it crashes due to limits.

My only other thought was the fact that we take what we get from codebase and convert it into a dynamic, but I'm pretty sure even dynamic objects are managed and therefore GC'ed when no longer needed.

@trevster344
Copy link
Contributor

trevster344 commented Jun 23, 2020

@RicardoJarree Are you using c465net.dll? I am using c4dll.dll but there are compiler switches in my Codebase.vb file for c465net.dll that link u4freeDefault so its more than likely the same method with a different name.

Would you say It's not possible that the code4init code is being run more than once? This sounds a lot like somehow one instance was created, and then another was created and the reference was lost to the first one. This would leave an orphaned CodeBase instance that would be a memory leak and unless you called code4init on the first prior to the second it wouldn't ever be cleaned up.

Your dynamic objects would be managed memory so a memory profiler wouldn't tell you it's unmanaged.

@mschifter
Copy link

mschifter commented Jun 24, 2020 via email

@RicardoJarree
Copy link

@trevster344 I'm using c4dll, I'm wondering if our Codebase.cs file might actually be doing funky bits with starting new instances. We abstract out the calls to a more simple interface, but this class tries to setup it's own instance as well, so if when we call a table the core Codebase.cs file is creating a new codebase instance then it will never get cleared.

I think I will take @mschifter idea and create a very simple console application which makes use of the Codebase.cs file and just opens one of the large tables and then tries to close it again. If that unallocates the memory then the issue is with what we are doing, if not then perhaps there is something wrong with our Codebase.cs file.

If it's not obvious yet, I've adopted this project 😉

@trevster344
Copy link
Contributor

@RicardoJarree If you would like to post the abstract code we can always do a little code review to help you out.

@mschifter
Copy link

mschifter commented Jun 25, 2020 via email

@phillipsawyer
Copy link

PR #10 has the official C# / VB.NET samples. Although limited and requires some fiddling, they are quite helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants