DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Page 1 of 3 123 LastLast
Results 1 to 15 of 33

Thread: Event hook causing memory leak

  1. #1
    Join Date
    Jul 2010
    Posts
    30

    Event hook causing memory leak

    Hi all,

    I have 2 classes, a base class and a derived class, the base class has a series of events to which the derived class responds , however after implementing the events the hooks are failing to release when the instance of the class is deleted, I set the hooks in the initialization of the class and (try) to release the hooks in the classes destructor, below is a partial listing of the classes:

    using namespace System::Runtime::InteropServices;

    using namespace System;

    public delegate void HowToTreatClassChanged();
    public delegate void DecimalLimitChanged();
    public delegate void TreatAllInstancesTheSameChanged();
    public delegate void HowToHandleRoundingChanged();
    public delegate void TreatAsComplexChanged();
    public delegate void RadixChanged();
    public delegate void SetAllInstancesEqualToBase();
    public delegate void SetAllHowToTreatClass();
    public delegate void SetAllDecimalLimit();
    public delegate void SetAllHowToHandleRounding();
    public delegate void SetAllInstancesTreatAsComplex();
    public delegate void SetAllRadix();


    namespace MyMath {

    namespace BigInteger{

    static public ref class BigInetegerBase
    {

    private:


    public:

    static event HowToTreatClassChanged^ OnHowToTreatClassChanged;
    static event DecimalLimitChanged^ OnDecimalLimitChanged;
    static event TreatAllInstancesTheSameChanged^ OnTreatAllInstancesTheSameChanged;
    static event HowToHandleRoundingChanged^ OnHowToHandleRoundingChanged;
    static event TreatAsComplexChanged^ OnTreatAsComplexChanged;
    static event RadixChanged^ OnRadixChanged;
    static event SetAllInstancesEqualToBase^ OnSetAllInstancesEqualToBase;
    static event SetAllHowToTreatClass^ OnSetAllHowToTreatClass;
    static event SetAllDecimalLimit^ OnSetAllDecimalLimit;
    static event SetAllHowToHandleRounding^ OnSetAllHowToHandleRounding;
    static event SetAllInstancesTreatAsComplex^ OnSetAllInstancesTreatAsComplex;
    static event SetAllRadix^ OnSetAllRadix;
    //
    //
    static void SetAllInstancesToBase();
    static void SetAllInstancesHowToTreatClassEqualToBaseValue();
    static void SetAllInstancesDecimalLimitEqualToBase();
    static void SetAllInstancesHowToHandleRoundingEqualToBase();
    static void SetAllInstancesTreatAsComplexEqualToBase();
    static void SetAllInstancesRadix();

    };

    public ref class BI sealed : BigInetegerBase
    {

    public:

    void SetAllRadixNow();
    void RadixChangeing();
    void HowToTreatClassChangeing();
    void DecimalLimitChangeing();
    void TreatAllInstancesTheSameChangeing();
    void HowToHandleRoundingChangeing();
    void SetAllInstancesEqualToBaseNow();
    void SetAllHowToTreatClassNow();
    void SetAllDecimalLimitNow();
    void SetAllHowToHandleRoundingNow();
    void TreatAsComplexChangeing();
    void SetAllInstancesTreatAsComplexNow();
    //
    ~BI(){

    delete MyNumber;
    delete _remainder;
    delete _asbinary;
    delete _basepower;
    delete _additionchain;
    delete _baseraised;
    delete _radixrep;
    this->OnHowToTreatClassChanged-=gcnew HowToTreatClassChanged(this,&MyMath::BigInteger::BI::HowToTreatClassChangeing);
    this->OnDecimalLimitChanged-=gcnew DecimalLimitChanged(this,&MyMath::BigInteger::BI::DecimalLimitChangeing);
    this->OnTreatAllInstancesTheSameChanged-=gcnew TreatAllInstancesTheSameChanged(this,&MyMath::BigInteger::BI::TreatAllInstancesTheSameChan geing);
    this->OnHowToHandleRoundingChanged-=gcnew HowToHandleRoundingChanged(this,&MyMath::BigInteger::BI::HowToHandleRoundingChangeing);
    this->OnTreatAsComplexChanged-=gcnew TreatAsComplexChanged(this,&MyMath::BigInteger::BI::TreatAsComplexChangeing);
    this->OnRadixChanged-=gcnew RadixChanged(this,&MyMath::BigInteger::BI::RadixChangeing);
    this->OnSetAllInstancesEqualToBase-=gcnew SetAllInstancesEqualToBase(this,&MyMath::BigInteger::BI::SetAllInstancesEqualToBaseNow);
    this->OnSetAllHowToTreatClass-=gcnew SetAllHowToTreatClass(this,&MyMath::BigInteger::BI::SetAllHowToTreatClassNow);
    this->OnSetAllDecimalLimit-=gcnew SetAllDecimalLimit(this,&MyMath::BigInteger::BI::SetAllDecimalLimitNow);
    this->OnSetAllHowToHandleRounding-=gcnew SetAllHowToHandleRounding(this,&MyMath::BigInteger::BI::SetAllHowToHandleRoundingNow);
    this->OnSetAllInstancesTreatAsComplex-=gcnew SetAllInstancesTreatAsComplex(this,&MyMath::BigInteger::BI::SetAllInstancesTreatAsComplexN ow);
    this->OnSetAllRadix-=gcnew SetAllRadix(this,&MyMath::BigInteger::BI::SetAllRadixNow);

    }
    //
    MyMath::BigInteger::BI::BI(): _i(MyMath::BigInteger::PowerOfIEnum::One), _mynumber(Basics::zero), _remainder(Basics::zero),
    _decimalplace(0), _be(BaseExponentEnum::NA), _accomputed(false), _instancedecimallimit(DecimalLimit),
    _instancecomplex(TreatAsComplex), _howinstancetreatsrounding(HowToHandleRounding), _lastinstanceradix(Radix),
    _instanceradix(Radix), bp(false), _howinstanceistreated(HowToTreatClass){

    _asbinary=gcnew array<bool,1>(1);
    _baseraised=gcnew array<java::math::BigInteger^,1>(1);
    //_basepower=gcnew array<BI^,1>(1);
    _additionchain=gcnew array<AChain^,1>(1);
    _radixrep=gcnew array<unsigned int,1>(1);

    _asbinary[0]=false;
    _baseraised[0]=gcnew java::math::BigInteger(Basics::strone,10);
    //_basepower[0]=gcnew BI();
    _additionchain[0]=gcnew AChain();
    _additionchain[0]->expval=0;
    _additionchain[0]->pos1=0;
    _additionchain[0]->pos2=0;
    _radixrep[0]=0;
    if(_howinstanceistreated==HowToTreatClassEnum::Fractions){

    _remainder=Basics::one;

    }

    this->OnHowToTreatClassChanged+=gcnew HowToTreatClassChanged(this,&MyMath::BigInteger::BI::HowToTreatClassChangeing);
    this->OnDecimalLimitChanged+=gcnew DecimalLimitChanged(this,&MyMath::BigInteger::BI::DecimalLimitChangeing);
    this->OnTreatAllInstancesTheSameChanged+=gcnew TreatAllInstancesTheSameChanged(this,&MyMath::BigInteger::BI::TreatAllInstancesTheSameChan geing);
    this->OnHowToHandleRoundingChanged+=gcnew HowToHandleRoundingChanged(this,&MyMath::BigInteger::BI::HowToHandleRoundingChangeing);
    this->OnTreatAsComplexChanged+=gcnew TreatAsComplexChanged(this,&MyMath::BigInteger::BI::TreatAsComplexChangeing);
    this->OnRadixChanged+=gcnew RadixChanged(this,&MyMath::BigInteger::BI::RadixChangeing);
    this->OnSetAllInstancesEqualToBase+=gcnew SetAllInstancesEqualToBase(this,&MyMath::BigInteger::BI::SetAllInstancesEqualToBaseNow);
    this->OnSetAllHowToTreatClass+=gcnew SetAllHowToTreatClass(this,&MyMath::BigInteger::BI::SetAllHowToTreatClassNow);
    this->OnSetAllDecimalLimit+=gcnew SetAllDecimalLimit(this,&MyMath::BigInteger::BI::SetAllDecimalLimitNow);
    this->OnSetAllHowToHandleRounding+=gcnew SetAllHowToHandleRounding(this,&MyMath::BigInteger::BI::SetAllHowToHandleRoundingNow);
    this->OnSetAllInstancesTreatAsComplex+=gcnew SetAllInstancesTreatAsComplex(this,&MyMath::BigInteger::BI::SetAllInstancesTreatAsComplexN ow);
    this->OnSetAllRadix+=gcnew SetAllRadix(this,&MyMath::BigInteger::BI::SetAllRadixNow);

    isin=666;

    isinitialized=true;

    }
    //
    MyMath::BigInteger::BI::BI( BI^ value) : _mynumber(value->MyNumber), _remainder(value->_remainder),
    _decimalplace(value->_decimalplace), _i(value->_i), _asbinary(value->_asbinary),_be(value->_be),
    _accomputed(value->_accomputed),_baseraised(value->_baseraised),
    _basepower(value->_basepower),_additionchain(value->_additionchain),
    _instancedecimallimit(value->_instancedecimallimit), _instancecomplex(value->_instancecomplex),
    _howinstancetreatsrounding(value->HowToHandleRounding), _lastinstanceradix(value->_instanceradix),
    _instanceradix(value->_instanceradix), bp(value->bp),
    _howinstanceistreated(value->_howinstanceistreated), _radixrep(value->_radixrep)
    {
    if(_howinstanceistreated==HowToTreatClassEnum::Fractions){

    if(_remainder->compareTo(Basics::zero)==0){

    _remainder=Basics::one;

    }

    }

    isinitialized=value->isinitialized;
    //Init();

    if(isin!=666){

    this->OnHowToTreatClassChanged+=gcnew HowToTreatClassChanged(this,&MyMath::BigInteger::BI::HowToTreatClassChangeing);
    this->OnDecimalLimitChanged+=gcnew DecimalLimitChanged(this,&MyMath::BigInteger::BI::DecimalLimitChangeing);
    this->OnTreatAllInstancesTheSameChanged+=gcnew TreatAllInstancesTheSameChanged(this,&MyMath::BigInteger::BI::TreatAllInstancesTheSameChan geing);
    this->OnHowToHandleRoundingChanged+=gcnew HowToHandleRoundingChanged(this,&MyMath::BigInteger::BI::HowToHandleRoundingChangeing);
    this->OnTreatAsComplexChanged+=gcnew TreatAsComplexChanged(this,&MyMath::BigInteger::BI::TreatAsComplexChangeing);
    this->OnRadixChanged+=gcnew RadixChanged(this,&MyMath::BigInteger::BI::RadixChangeing);
    this->OnSetAllInstancesEqualToBase+=gcnew SetAllInstancesEqualToBase(this,&MyMath::BigInteger::BI::SetAllInstancesEqualToBaseNow);
    this->OnSetAllHowToTreatClass+=gcnew SetAllHowToTreatClass(this,&MyMath::BigInteger::BI::SetAllHowToTreatClassNow);
    this->OnSetAllDecimalLimit+=gcnew SetAllDecimalLimit(this,&MyMath::BigInteger::BI::SetAllDecimalLimitNow);
    this->OnSetAllHowToHandleRounding+=gcnew SetAllHowToHandleRounding(this,&MyMath::BigInteger::BI::SetAllHowToHandleRoundingNow);
    this->OnSetAllInstancesTreatAsComplex+=gcnew SetAllInstancesTreatAsComplex(this,&MyMath::BigInteger::BI::SetAllInstancesTreatAsComplexN ow);
    this->OnSetAllRadix+=gcnew SetAllRadix(this,&MyMath::BigInteger::BI::SetAllRadixNow);

    isin=666;

    }

    }
    //

  2. #2
    Join Date
    Nov 2003
    Posts
    4,118
    You're using Managed C++, not standard C++, so the behavior of your code is different. I can't tell whether there's a memory leak here but the destructors aren't responsible for releasing GC memory. That memory is released when the GC is invoked, and that's completely up to the implementation (e.g., the Managed C++ runtime), not your classes.
    Danny Kalev

  3. #3
    Join Date
    Jul 2010
    Posts
    30
    There is definately a memory leak because when I run the application I can watch the mem usage go from about 25k to over 500k in a few seconds, I know its coming from the event hooks because if I comment out the hooks it runs fine, and I also know that it is being caused by the temporary variables (of type BI which is the derived class) in the overloaded operators, what I dont understand is why these instances (especially the hooks) persist after I call the -= on the hooks and then delete the temporary variables. After quite a few hours of reading, I am thinking it has something to do with the fact that the base class is static and therefore outlives the instances lives, and for some reason wont release the hook (even after I explicitly unhook the methods from the delegates). I tried creating another method that just removed the hooks and calling it before deleting the instance but that didnt even put a dent in the problem.

    On the subject of my writing this in managed code, would native c++ have been better? I am just learning c++ but have a pretty strong background in Basic and having a hard time of changing my thinking to c++, I also thought that since managed c++ handles the gc it would be easier to learn this way, I tried briefly to write it in native c++, but didnt spend the time to figure out what all the errors that came up where, and seeing how the class is up to about 21,000 lines of code, I didnt want to rewrite the whole thing lol.

  4. #4
    Join Date
    Dec 2003
    Posts
    3,366
    Managed code is terrible: it will insist that legal, working, valid C++ is wrong and force you to "fix" it while teaching you things that are nonstandard and convoluted. The only reason to use it is if your project already has it (someone elses mistake) or you absolutely have to have one of the features that only works when it is turned on.

    The best way to find your leak is to put in trace code, IMO. Just add print statements and pauses (sleep for 1/2 second, for example) that tell you when memory is allocated and how much, and when it is destroyed and how much. You should, if your program is slurping up memory as you described, see a pattern of print statements about ALLOCATED 1k bytes to variable XYZ over and over without corresponding delete statements.

    Its too much code to find it by hand by visual inspection, I looked but between the oddities of the managed code and the volume of code, I did not see anything.

  5. #5
    Join Date
    Nov 2003
    Posts
    4,118
    The increase in memory usage doesn't necesarily indicate a leak. You can't tell whether the OS reclaims that memory later (next week? next month?) or not.
    Yes, with native C++ you have tight control over the memory usage, which is exactly why hard-core C++ers don't want a GC getting in their way: you know exactly when the memory is released: when the program deletes it. But of course, this determinacy has a price too (bugs. design complications etc.) the bottom line however is this: if you're used a GC, don't expect the program to behave as native C++ would. These are two different worlds.
    Danny Kalev

  6. #6
    Join Date
    Dec 2003
    Posts
    3,366
    Thats a good point --- is there a "force GC" command you could use to check it out? I do not know enough about the managed GC code, but if such exists, you could apply the force to see if the memory is leaked or just marked for deletion at a future time.

  7. #7
    Join Date
    Jul 2010
    Posts
    30
    jonnin, I remember reading somewhere about a way to force gc Im going to look for that again after this reply.

    Danny, I let the program run as long as it could till it locked up, then ran it again and paused it in the debugger to see if it would release the memory. When I run my program without the hooks, it runs stably at around 30k (according to task manager), but with the hooks it eats memory like crazy. I used clrprofiler last night and after running the program for only about 10 seconds, it had accumalted over 70,000 instances in that time. I am reading up on the profiler to figure out exactly what all the information means. what gets me is it looks like the references to the hooks are not deleting (they are ALL still listed in the profiler) and that was after I had stepped through the code to make sure that the callls to remove the hooks were being hit. I am not sure if the gc still works when I have the program paused in debug mode, but I cannot let my current algorithm just run because in less then 2 minutes my computer becomes completely unresponsive. I am thinking of writing a shorter method to test it out now.

    Ive prided myself for learning as much as I have on my own (thanks to an enormous amount of research on my part when stuck and usually finding my answer either on these boards or codegurus boards), but I am stumped on this problem.

    I have been thinking over the last month or so I should have started out learning how to write correct unmanaged code and am not sure if I should invest the time to finish this project in managed code, or put it on hold while I start teaching myself native c++, after reading yalls replies it sounds like Id be learning another language when I still havent got the managed side of it figured out yet. Any good recomendations on a good book on the subject? (preferably affordable since I am just a lowly carpenter that just enjoys tackling a problem)

  8. #8
    Join Date
    Dec 2007
    Posts
    401
    > a way to force gc Im going to look for that again after this reply.

    Code:
    GC::Collect();
    Console::Write( "Memory usage after full collection: " +  
                                GC::GetTotalMemory( true ).ToString() + "\n"  ) ;
    This may not give you as much joy as you would expect (for one thing, it is a performance drag; for another the GC has it's own mindset about how much memory it should release ).

    A better approach would be to not create all these thousands of instances every second; that usually results in terrible consequences in virtualised execution environments with automatic garbage collection. See if you can reuse the same object again instead of destroying it and creating another one afresh.

  9. #9
    Join Date
    Jul 2010
    Posts
    30
    All those objects would fall out of scope anyways when the method they are created in was completed, the class makes heavy use of the repeated square and multiply and the left to right binary exponentiation algorithms whenever used with encryption and thats what generates all the calls to the multiply routine while my implementation of modular reduction uses the division routine. not to mention when I set the class to handle the numbers as irrational or as fractions for my math class those calls jump dramatically. I know there has to be a cleaner way to write the class, but as I said I am still learning.

    In truth, I could probably set it up to where it didnt create about 1/2 of those temporary variables, but the other half Id be hard pressed to get rid of and still have the functionality.

    btw, thanks for the garbage collection tip, I was just getting ready to look for that again, unfortunatly it still didnt free the memory, even after I let my application run through a method( which just did 1000 modular exponentiations then the method ends) and called to the gc, it never freed it even after setting idle for about 15 minutes.

    Right now, I am running it without the events (works great without them) but the events would make certain situations a lot easier.

    Also I like to know if an abstract base class is only created once per application, or just once on the machine its running on?

  10. #10
    Join Date
    Dec 2007
    Posts
    401

  11. #11
    Join Date
    Dec 2003
    Posts
    3,366
    even though I dislike managed code, the more you know, the better, so learn to do things both ways (pure c++ and microsoft C++).

    There are threads here on good books -- but you want to look for newer books as there is a new standard that either just came out or is about to come out (due to beta/pre-releases, its hard to put a finger on when something is officially "OUT" if one does not follow it closely and I do not care to follow it that close). The older the book is, the more likely it will teach you something that has changed, so any book older than 2005 is probably bad to start with (but, many of these books have a great deal to offer once you know the language!).

    As for how to do things, here are some ideas:

    static variables. These can create problems with threaded applications, and with multiple core processors, most programs *should* be threaded if they tap the cpu to any real extent. Certainly encryption, where you may be tasked to encrypt huge files, should be threaded to double the throughput. Static variables exist for the life of the program, and careful use of them (again, be aware of threading issues!!!) can allow subroutines to maintain a set of temporary storage variables without creating/destroying them all the time. (this is the time/space tradeoff: in a program you often choose to make a program use less resources (space!) or take less time, and when you choose, the other one increases. For example, you could store the factorial value in a table of every for 1-100 factorial, which wastes 100 memory spots (for 64 bit integers, thats 6k memory) or you can compute it recursively (for 100 factorial, thats 100 multiplications and 100 function calls!). The first method takes less time and uses more space, the second uses less space and takes more time...)

    Your own GC. Complex, but in regular c++ you can, instead of deleteing memory, just make it into a stack/linked list. Then, instead of allocating memory, you pop it back off the stack. If the stack is empty, let the system ask for memory as you are already doing, but if you have old memory that was "deleted" you just reclaim it. Memory allocation is expensive (cost = time = money). I suspect you can do this in managed code too: the act of storing the memory on the list should make a reference count to it, which should prevent its deletion. This really only works "well" (due to complexity issues) if the memory blocks that you allocate and delete are all the same size; trying to manage generic memory (any size blocks) is a bad idea (find the largest block size you need and always allocate that much).

    You can also look into STL containers, which can manage memory for you to an extent. Valarray, for example, seems custom made for the backbone of a big integer class.

  12. #12
    Join Date
    Jul 2010
    Posts
    30
    Honing in on the source of the problem. I now know that the instances created inside the class are not being destroyed, the instances created outside the class (in my test program) are destroying the event hooks and the instances of my class just fine. The debugger will not even let me attach a break point to the delete statements that are internal to the class, but it does let me attach brakpoints to the delete statements (the ones deleteing instances of my class) in my test program. Am I supposed to use a different pattern to destroy these variables ?

    vijayan:

    Thanks for the articles, while it doesnt show me where I am going wrong, it would probably provide a temporary solution till I figure out the problem.

    Jonnin:

    The only place I use static variables is in the base class, and the only thing the base class holds are the parameters for how the class as a whole is supposed to initialize and operate. As for stl....I looked at it once for about 10 minutes but did not dive into it (there are quite a few pieces to the c++ puzzle lol). If I try rewriting this in unmanaged c++, will it still work with managed code easily? the only reason I ask is because the only way I have found to work with forms in c++ has been in managed code (so far at least), and I use forms for all my testing Ive got about 500 labels on the current form I am using for testing this class and I doubt very seriously if I could kick out a console app that could format all that data as quickly as I can create a form for it.

  13. #13
    Join Date
    Dec 2003
    Posts
    3,366
    I have never used managed code and I sometimes use dialogs / forms to test things. Usually its easier to just test code with console and print statements --- the act of adding a form adds complexity, confusion, and bloat that make testing more difficult than it needs to be (unless what you are testing actually is part of a GUI!). But that does not matter, point is managed code is not required to use a form, you can use MFC, or you can actually (this is not trivial) just call the windows library functions directly, if you look at the masm examples it creates a notepad application in assembly language by tapping the system dlls.

    static variables are a tool, use them as you see fit. A lot of my code is mathematical in nature & needs to run fast. Having temporary variables exist all the time rather than create/destory over and over saves a LOT of cpu time, time that is wasted doing nothing except creation and destruction of memory. To stop the waste I use static variables. However, I tend to ingnore OOP rules that get in my way, so if you are the type that gets bent out over such things, take any advice I give with a grain of salt. I have even been known to write functions that are not members of a class, of all things ;)


    As for forms vs console testing/debugging/etc, if the data is as large as yours I would write it in a CSV file and let excel format it for me if possible. If the data is too large for *that* to be easily manage, its probably too big for *me* to manage either, so I would break it into multiple excel files if possible or organize it some other simple way. If forms work for you, go for it. For me, I try to reduce units to their bare bones to make testing and debugging as easy as possible --- forms simply add too much additional code to step around when trying to find a problem, at least for me.

    Note that using forms is not pure C++, you still have to use a library even if its not managed. Pure c++ is unaware of the OS and its libraries, graphic, or anything of this nature. So it means using microsoft's libraries and including their headers, changing the compiler settings from console app to one that uses the extended stuff, etc. So its still not pure c++. The only way to do it in pure c++ is text on the console.
    Last edited by jonnin; 07-23-2010 at 01:51 PM.

  14. #14
    Join Date
    Jul 2010
    Posts
    30
    I could put the data into a csv file, Ive actually done quite a bit of work in excel, but I did it in vb not c++(just learning), I guess if Im going to try working in unmanaged code Id better get used to working with formatting my data in a console app, wouldnt be much different from when I first learned basic on a trs80 (with a whole 8 colors woohoo).

    It still frustrates me that I have not solved the problem at hand though, I know now that the problem is not actually with the event hooks, it is a problem with the flow of the program. It appears that after a return statement, it will not hit any other statements in the function, so none of the delete statements after the return are firing, and this is only so inside the class (outside as in my test form the delete statements are being hit), I am going to rewrite part of it so that all but the actual variable holding the return value are deleted BEFORE the return statement. I understand most of you dont use managed code, but you should beable to put your delete statements at the end of the function after the return statement shouldnt you? Or is there a setting somewhere or something I did to create this behavior?

  15. #15
    Join Date
    Nov 2003
    Posts
    4,118
    No. You can't put any statement after a return statement because those statements are unreachable (I'm surprised that your compiler didn't issue warnings about this). Notice that any other break statement (goto, throw, break etc.) might cause the program to skip statements so if your delete statements might be skipped, you should either move them elsewhere or replace raw pointers with smart pointers. C++ has at least two such pointers: shared_ptr and auto_ptr (the latter is deprecated and has peculiar semantics but it's useful in many cases still).
    Danny Kalev

Similar Threads

  1. Possible Memory Leak in Java application
    By esi-eric in forum Java
    Replies: 3
    Last Post: 02-24-2005, 07:58 PM
  2. Announcing a memory leak in javax.comm
    By Jason Jakob in forum Java
    Replies: 0
    Last Post: 06-30-2002, 01:14 PM
  3. help memory
    By kathy in forum Java
    Replies: 0
    Last Post: 11-02-2001, 05:22 PM
  4. Interface leaks in C#?
    By Kevin Burton in forum .NET
    Replies: 12
    Last Post: 10-09-2000, 10:29 AM
  5. Re: MS Provider For Oracle : Memory Leak ?
    By John Grandy in forum VB Classic
    Replies: 0
    Last Post: 04-08-2000, 08:35 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center