Re: What is the major drawback of C# .NET?
No, I think the only mistake those people at MS are doing is to try to make non-programmers able to program. They try to make everything so easy, that in the end, for me, everything is getting more and more unusual.
The best example are the good old destructors and all that "manual garbage collection" the programmer did himself. Believe me, that days, my applications needed less memory and had no leaks! Today, my app grows up to 500 (!!!) MB.
I do not think that each and every person has to be able to write programs. The technology that is necessary for this (->.net) handicaps professional programmers more than it helps the other people.
hope you could understand me.
kind regards
thegrinch
Re: What is the major drawback of C# .NET?
Quote:
The best example are the good old destructors and all that "manual garbage collection" the programmer did himself. Believe me, that days, my applications needed less memory and had no leaks! Today, my app grows up to 500 (!!!) MB.
1) it is extremely doubtful that all of your programs never had a memory leak even in the event of all possible exceptions.
2) Who care about the memory footprint. If your computer has 1GB and nothing else is running, then the program SHOULD make use of the available memory. [Which is why GC does not invest any effort until there is memory pressure, there simply is no point].
(As I have said many many times) I have been a professional developer for over 30 years, and C# has provided the most robust and effective environment I have worked in (for general business type applications).
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by cjard
Can someone with a good web browser please save
http://c#.net onto a floppy disk and post it to me?
I've found a mirror site: http://www.seesharp.com/
Hey, look: 'THIS DOMAIN IS FOR SALE'
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by Zaccheus
Zaccheus << "SMACK!"; :D :D :D
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by TheCPUWizard
2) Who care about the memory footprint. If your computer has 1GB and nothing else is running, then the program SHOULD make use of the available memory. [Which is why GC does not invest any effort until there is memory pressure, there simply is no point].
But the concept of managing the memory (in software) is slowing down everything. There is always a small "delay". This was in the good old WinAPI and MFC times not the case, you always got a direct immediate reaction.
I am extensively doing numerical computations, and I can tell you about very bad performance of .net apps. This also must be the case, if each and every memory access is "checked for validity".
Regards
thegrinch
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by thegrinch
No, I think the only mistake those people at MS are doing is to try to make non-programmers able to program. They try to make everything so easy, that in the end, for me, everything is getting more and more unusual.
The best example are the good old destructors and all that "manual garbage collection" the programmer did himself. Believe me, that days, my applications needed less memory and had no leaks! Today, my app grows up to 500 (!!!) MB.
I think this is an oversimplification. Okay modern OO languages like C# and Java are simpler than C++ in the sense that the syntax is cleaner and that the number of options have been reduced, but these languages are harder in many other ways. The emphasis in C# and Java is much more on OO techniques and the efficient use of powerful data structures. So although inexperienced programmers maybe make less traditional "shot in the foot" errors, they tend to make mistakes at a higher level like bad OO designs and use of inappropriate data structures.
So in my view the introduction of C# and Java hasn't made programming any easier, rather harder.
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by thegrinch
But the concept of managing the memory (in software) is slowing down everything. There is always a small "delay". This was in the good old WinAPI and MFC times not the case, you always got a direct immediate reaction.
Actually in many circumstances the exact oposite is true. Every time you call delete in a native application there is a delay while the heap status is updated (marking the block as free, checking for adjecent blocks, collapsing free blocks, etc). With garbage collection, this does not happen!
The actual overall time is moved to the point where you are going to attempt an allocation. Unlike the claims by many, this timing is extremely predictable, if you are aware of the state of the entire system.
Quote:
I am extensively doing numerical computations, and I can tell you about very bad performance of .net apps. This also must be the case, if each and every memory access is "checked for validity".
I also do some very intensive numerical applications [processing 256 channels of audio with 256 dynamic "parameters" at a frame rate of over 30fps] Many of these are highh/low/band/gap/comb filters, or other dsp algorithms.
I have absolutely no problems, but I have been very careful about allocations and effects on the GEN0, GEN1, GEB2, and LO heaps. Have you considered all of these things ars you were designing and implementing the code? Can you go through all (or at least a significant portion) of your object instances and references and determine the lokelyhood of which generation will collect them? Can you go through 100% of your objects and determine which are on the LOH? Have you used perfmon (or another tool) to measure the frequency/duration of your collections?
I do not mean this personally, it is jut that the vast majority of people writing managed code, and attempting near-realtime or true realtime applications have not taken these items into consideration. The single biggest issue (which takes many forms) is holding on to references to information for longer than necessary. Consider:
"conventional code" (pseudo)
Code:
SomeType *info;
info = new SomeType();
// do some things with info
....
// do some things that do not use info
...
// do some things with info (that to not require state of the info instance from above
...
delete info;
This is typically a bad implementation in managed code.
"conventional code" (pseudo)
Code:
SomeType *info;
info = new SomeType();
// do some things with info
delete info;
....
// do some things that do not use info
...
info = new SomeType();
// do some things with info (that to not require state of the info instance from above
...
delete info;
If one cannot explain why the second is (typically) much better than the first, then they do not understand the environment.
:wave: :wave:
thegrinch[/QUOTE]
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by TheCPUWizard
If one cannot explain why the second is (typically) much better than the first, then they do not understand the environment.
I can explain why both are bad. :)
In the first case you may introduce a delay which translates into an unresponsiveness in the GUI. In the second case this is unlikely but it can still happen because you don't control when the GC decides to do kick in and do something. The whole issues should instead be resolved using threading so that extensive work is offloaded from the GUI thread.
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by _uj
I can explain why both are bad. :)
In the first case you may introduce a delay which translates into an unresponsiveness in the GUI. In the second case this is unlikely but it can still happen because you don't control when the GC decides to do kick in and do something. The whole issues should instead be resolved using threading so that extensive work is offloaded from the GUI thread.
_uj,
Yes "work" should be done in a background thread if there is a UI. But that actually has nothing to do with the post. Assume a somple condition where a person is going to run a simple program from the command line, that will output results at the end. Assume program is simple and single threaded.
There is still a very significant difference between the two code samples I provided. If it is not immediately apparent what it is then [IMHO] it is unlikely that the reader will be capable of developing high performance managed applications.....
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by TheCPUWizard
_uj,
Yes "work" should be done in a background thread if there is a UI. But that actually has nothing to do with the post. Assume a somple condition where a person is going to run a simple program from the command line, that will output results at the end. Assume program is simple and single threaded.
There is still a very significant difference between the two code samples I provided. If it is not immediately apparent what it is then [IMHO] it is unlikely that the reader will be capable of developing high performance managed applications.....
Well, you quoted thegrinch and I got the impression it was about GUI responsiveness.
Anyway I don't see the significant difference between the two code examples. Maybe you would care to explain.
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by _uj
Maybe you would care to explain.
Well since you ask, and no one seems to be jumping on providing the answer.... :D
In the first case the info instance of SomeType is kept for the entire routine.
If
Code:
// do some things that do not use info
performs any allocations that would trigger a GC, then the instance will not be collected, and will be premoted from Gen0 to Gen1. This means that it will never be collected no matter how many Gen0 (the cheapest) are performed even after the routine exits.
Even worse is if the intermediate code does enough allocations that a Gen1 collection is performed, at this point, the object will persist until the next Gen2 (the most expensive) collection is performed.
So simply holding on to a reference for a few lines of code (especially if those lines either allocate, or call routines that allocate, or exist in a multithreaded environment where other threads might allocate) can have a potentially severe impact on system performance.
The second example addresses this. The reference is help on to for the absolute minimum time that it is needed. This allows the GC to run much more effectively.
---------
Test this on your (every reader of this thread who writes managed code). Use perfmon.exe (if you don't know what that is, go learn no, it is one of the most valuable system tools. Set it up to measure the following:
1) # of GEN0 collections
2) # of GEN1 collections
3) # of GEN2 collections
4) %Time spend in GC.
5) GEN0 Heap Size
6) GEN1 Heap Size
7) GEN2 Heap Size
8) Large Object Heap Size
If your progam is written well you should see one of the following:
1) Your program does all of it's allocation somewhere at startup. Therefore there will be very few if any executions of the CG. This condition is both rare and typically not found.
or
2) There are Gen0 collections happening on a fairly regular basis, little or no memory is being premoted to the Gen2. Gen1 collections tend to coincide with the frequency and occurance of "top level operations", and the Large Object Heap is small (ideally) or at least FLAT. If these conditions are met, ten it is typical to find less than 2-3% of the time spend in GC (average).
Unfortunately, unless the developer was very aware of conditions like I posted earlier (as well as making sure that objects which implement IDisposable are ONLY created and used from within "using blocks", and no references are held except for the one controlled by the using clause), it is quite likely that you will see creep into the Gen2 heap with either the total foot print of your program growing, or a large amount of time spend in the GC.
-------------------------------
The bottom line is that while the GC does inherently minimize managed memory leaks, it does NOT remove the responsibility of effective management from the programmer. This often involves a paradigm shift (mindset change) that is as (or more) significant than the shift that occured when switching from "structured programming" in "C" (or Fortran, Cobol, Pascal), to an "Object Oriented Programming" approach in C++, or.....
The biggest difference is that there was significant awareness that there was a shift from SP to OOP. But many (most?) developers are painfully ignorant of the many things that have to be done properly..
[Are you 100% confident the for EVERY "event += delegate" there is a cooresponding un-registration if you object is not being actively used while the object containing the event is still in use??? Even under all exception conditions?????]
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by TheCPUWizard
Well since you ask, and no one seems to be jumping on providing the answer....
You posted pseudo-code similar to C++/CLI but what's the equivalent in C#?
Quote:
So simply holding on to a reference for a few lines of code (especially if those lines either allocate, or call routines that allocate, or exist in a multithreaded environment where other threads might allocate) can have a potentially severe impact on system performance.
The second example addresses this. The reference is help on to for the absolute minimum time that it is needed. This allows the GC to run much more effectively.
In general I don't believe in "helping" the GC so I think your reasoning is flawed apart from maybe in some very special cases.
It really boils down to how likely is your scenario and how severe is the impact? Statistically how often will an object which is used strictly locally to a method get "accidentally" promoted to a higher GC generation? My guess is that this is extremely rare and nothing to bother about. If I'm right then your optimization actually slows things down because of the extra object creations it requires.
A much better rule is to avoid finalizers because objects sporting them will always be promoted to the highest GC generation (and thus always be GC expensive).
As a sidenote there's an optimizing technique called escape analysis. It means that the compiler automatically detects local-to-method objects. It can then allocate such objects on the local stack, or on the heap but treat them outside the generation system and discard them together with the stack when the method is left. Maybe the .NET compilers have escape analysis? In any case it would render your optimization unnecessary.
As another sidenote, C++/CLI allows you to declare reference variables in methods to have stack semantics. If you do, in principle you have made the escape analysis for the compiler and such objects could be handled very efficiently totally avoiding the GC cycle.
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by _uj
You posted pseudo-code similar to C++/CLI but what's the equivalent in C#?
Just setting the reference to null is sufficient if there is no IDisposable or finalizer...
Quote:
In general I don't believe in "helping" the GC so I think your reasoning is flawed apart from maybe in some very special cases.
Actually I have made a significant part of my living for the past 4 years in this exact arena. If you do not write code that is designed to work well in a garbage collector environment, and do not know the basic strategy of the GC, then you WILL write POORLY PERFORMING code.
Quote:
It really boils down to how likely is your scenario and how severe is the impact? Statistically how often will an object which is used strictly locally to a method get "accidentally" promoted to a higher GC generation? My guess is that this is extremely rare and nothing to bother about.
You have to TEST each occurance. Put a WMI sentinal at the beginning and end of a code block. Use perfmon. If objects get promoted while the sentinel is active, then this IS occuring.
Quote:
If I'm right then your optimization actually slows things down because of the extra object creations it requires.
The allocation of a new object is effectively
Code:
pointer =gen0ptr;
gen0ptr += sizeof(newObject);
return pointer;
On most machines this executes in well under 1uS (one millionth of a second), rarely significat.
Quote:
A much better rule is to avoid finalizers because objects sporting them will always be promoted to the highest GC generation (and thus always be GC expensive).
Basically true, but nowhere have I mentioned finalizers, except indirectly when I mentioned IDIsposable. Owhich have finalizers should implement IDisposable, and IDisposable object should always be properly guarded to make sure Dispose is called, which in durn should cal SuppresssFinalizer(), so for performance Finalizers will NEVER execute.
[quote]
As a sidenote there's an optimizing technique called escape analysis. It means that the compiler automatically detects local-to-method objects. It can then allocate such objects on the local stack, or on the heap but treat them outside the generation system and discard them together with the stack when the method is left. Maybe the .NET compilers have escape analysis? In any case it would render your optimization unnecessary.
[quote]
Once the last use of an object is detected within a scope, the compiler is free to (and in many cases will) allow the object to be collected. The usage of the instance at the bottom of my original sample however would proclude this from happening (and is why the sample has all three parts rather than just the first two...
Quote:
As another sidenote, C++/CLI allows you to declare reference variables in methods to have stack semantics. If you do, in principle you have made the escape analysis for the compiler and such objects could be handled very efficiently totally avoiding the GC cycle.
True, but there are issues with stack semantics also. For example, it does NOT adddress the issue I have outlined...
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by TheCPUWizard
Actually I have made a significant part of my living for the past 4 years in this exact arena. If you do not write code that is designed to work well in a garbage collector environment, and do not know the basic strategy of the GC, then you WILL write POORLY PERFORMING code.
And the best way to do that is to follow the golden rule of GC. Allocate new objects when you need them and then just stop using them when you don't need them anymore.
The GC comes with a certain overhead so in general one should avoid extensive object creations but that's basically a design issue. See for example the Flyweight pattern. One should also avoid so called unvoluntary object retention, that is to unwittingly hold on to objects that are no longer needed.
Trying to second-guess and "help" the GC is not good. In fact that's often the cause of bad GC performance. Modern GC's are extremely efficient. They know more about your program than you ever will. Just leave object management to the GC and you get the best results.
If the GC turns out to be the problem then it's highly likely that the application, or parts of it, shouldn't use one in the first place, or use a deterministic GC instead. This is typical of the "optimization" you're suggesting. You're just tuning the symptoms, not solving the problem.
Quote:
Basically true, but nowhere have I mentioned finalizers,
I mentioned finalizers as something to generally avoid because it's known to slow down recycling of objects for sure.
Quote:
True, but there are issues with stack semantics also. For example, it does NOT adddress the issue I have outlined...
It certainly does in the context of the escape analysis I was talking about. This allows a compiler to render your "optimization" completely unnecessary. The object you're trying to make sure will stay in the lowest GC generation won't even enter the GC cycle.
Re: What is the major drawback of C# .NET?
Quote:
Originally Posted by _uj
And the best way to do that is to follow the golden rule of GC. Allocate new objects when you need them and then just stop using them when you don't need them anymore.
100% true, but it is amazing how many people hold on to them much longer than necessary (e.g. using a member variable with the life of your object rather than local variables within the method
Quote:
The GC comes with a certain overhead so in general one should avoid extensive object creations but that's basically a design issue. See for example the Flyweight pattern.
Here we differ. as I mentioned before the "overhead" of object creation is (approximately)
Code:
pointer =gen0ptr;
gen0ptr += sizeof(newObject);
return pointer;
When the GC runs, it starts with all rooted references and walks the object tree. (Assuming a Gen0 or Gen1 collection), any objects still in existance get COPIED to the next generation, and all of the pointers that reference it updated [this is overhead!], the heap pointer then gets set back to the base:
Code:
gen0ptr = gen0base;
So if during the timespan between collections you generated a few million objects that you no longer had references to, then ther would be the (again sub microsecond) allocation cost mentioned above), but there would be absolutely 0 overhead during the garbage collection phase.
In fact, the term "Garbage Collection" is really a misnomer, and there have been many articles written about this. What actually happens is that all valid objects are collected individually, and all of the garbage is evaporated with a single machine language instruction (or two).
Quote:
One should also avoid so called unvoluntary object retention, that is to unwittingly hold on to objects that are no longer needed.
Again we agree, see my first response in this reply!
Quote:
Trying to second-guess and "help" the GC is not good. In fact that's often the cause of bad GC performance. Modern GC's are extremely efficient. They know more about your program than you ever will. Just leave object management to the GC and you get the best results.
If you are talking about having GC.Collect(...) in your code, you are 100% right. This should never be done.
Quote:
If the GC turns out to be the problem then it's highly likely that the application, or parts of it, shouldn't use one in the first place, or use a deterministic GC instead. This is typical of the "optimization" you're suggesting. You're just tuning the symptoms, not solving the problem.
Again, just based on my exprience, improper design that does not account for the behaviour of the GC is the root cause. But as the lyric goes "It's just my job 5 days a week"...
Quote:
I mentioned finalizers as something to generally avoid because it's known to slow down recycling of objects for sure.
YUP. In fact some of my classes the I want ro really make sure properly get disposed have a finalizer that throws and abort exception (in development builds). If Dispose is properly invoked, then the finalizer never runs, otherwise I get to find and fix the problem.
(emphasis added for context).
Quote:
It (stack allocation) certainly does in the context of the escape analysis I was talking about. This allows a compiler to render your "optimization" completely unnecessary. The object you're trying to make sure will stay in the lowest GC generation won't even enter the GC cycle.
You are correct that the object itself will have the duration of the stack frame and will not enter into GC (but again remember objects with no references impose 0 cost at GC time), however it CAN make things worse...
Code:
class MyBadClass
{
public MyBadClass()
{
for (int i =1; i<2000; ++i)
m_MyList.Add(new char[7500]);
}
private
ArrayList m_MyList = new ArrayList;
}
If you instanciate this on the stack, there is no way to release the object (and thus the memory in use by the internal array) until the stack frame exits. If a GC occurs at any point after the object is created on the stack, then the 2,000 objects in the array list will all get promoted to GEN1 (occuring a cose).
If, the instance of MyBadClass had been created on the heap and used for a duration shorter than the duration of the stack frame, this situation could have been avoided.
}