views:

47

answers:

2

I wrote a custom control in C# that inherits from the RichTextBox. The purpose of this control is to contain all improvements and changes, such as modified line numbering and having the control repaint itself only when it should.

Yesterday, I noticed memory spikes (and often, OOM exceptions) when accessing the Lines property of this control (there are 600,000+ lines in the control at times). I coded workarounds that no longer involve it, but I would still like to completely remove it so people who use my control in the future do not use it.

The Lines property is System.Windows.Forms.TextBoxBase.Lines. Ideally, I'd like the string[] for this property to never be touched; when I load text in the control, I do NOT want the control to do anything to fill this lines property (because it's completely pointless and is consuming some time and resources).

Anyone have any ideas?

EDIT: I tried

        public override string[] Lines
        {
            get { return null; }
            set { ; } // do nothing
        }

But VS says "cannot override inherited member System.Windows.Forms.TextBoxBase.Lines.get because it is not marked virtual, abstract, or override.

So it looks like I can't override or remove it. I think the RichTextBox is setting the property because it is filled after change the text. Is there a way for me to capture and handle that message?

A: 

Have you tried to shadow the property?

public new string[] Lines
{
   get { throw new Exception("Not supported"); }
   set { throw new Exception("Not supported"); }
}
Steve Danner
+2  A: 

Hmya, it is only going to slow down a decent programmer for no more than 5 minutes:

string[] lines = ((RichTextBox)myEditor1).Lines;

which will blow just as hard. There isn't much point in trying to prevent usage of your class that can be used anyway. The Lines property ought to be useful to anybody that uses your editor, it covers the very basic need to be able to retrieve the text that was edited. Don't throw out the baby with the bath water.

The real problem here is that RTB uses so much unmanaged memory to store the text, leaving little left for the garbage collected heap. It gets really slow too once you pump thousands of lines into it. No component should ever be allowed to swallow up half of all available memory. Either limit the number of lines you allow to edit or use a better editor, like ScintillaNET.

It is also rather important to be a pragmatic programmer. Beyond hiding a property needlessly. 600,000 lines in a text box is an enormous number. There a 3/4 million words in the Bible, you are displaying 6 copies of the Bible in your text box. No sane human is ever going to read that, they'll just dislike your program intensely. Not just because it is impossible to use effectively but also because it is a crash bucket.

Hans Passant
+1 Deleted my upvoted answer, I think this is a much better answer.
GenericTypeTea
"The Lines property ought to be useful to anybody that uses your editor, it covers the very basic need to be able to retrieve the text that was edited."Well, generally the user won't be editing the text. The control is designed mostly for viewing with a bunch of little features (formatting certain text, etc). Whenever the program needs the current line, I use a temp variable starting at the SelectionStart and back up to the previous linefeed. I then concatenate the strings until the next linefeed. This is faster than calling editor.Lines[GetLineFromCharIndex(editor.SelectionStart)].
Kizaru
Also, the memory usage doesn't spike up when doing my workaround. I spent weeks a couple of months ago trying to find a better editor, but they all had massive issues. ScintillaNET's only issue was memory leaking (which lead to OOM) when changing the text. Although this project is done and considered more than satisfactory, I'd still like to find ways to improve it :)
Kizaru
If the project is done then it is pretty unlikely anybody is still going to try to use the Lines property?
Hans Passant
The control will be reused. And it appears the TextBoxBase.Lines property is being set by the RichTextBox on load, which is using some resources. That's another reason why I want to remove it.
Kizaru
Added a note about dealing with problems like this pragmatically.
Hans Passant
Of course no sane human would ever read 600,000 lines. The purpose of the program is to parse logs. It shows the full log and the results of the parse or search (with many features to navigate around the log for certain areas pertaining to parsed output). 60MB files (~650,000 lines) are the maximum size of our logs. If you perform a search that returns every single line, the program is using ~180MB max after the search. During the search, it may reach up to 250MB (this is what task manager says, which could be higher). The control will be reused in other software.
Kizaru