Runtime Compilation - Worth It?
-
I'm looking for opinions here, so if the subject interests you, please reply. In the following post, runtime compilation is used to mean simple-to-use, on-the-fly access to the compiler, beyond
eval
statements, extending to the ability to compile full methods, classes, and assemblies. 1) Is runtime compilation worth the overhead (both in actual runtime cost and in time to implement/use)? 2) Is the ability to unload a previously loaded Assembly (possibly automatically, integrated into the garbage collector) important? 3) WARNING, Long Question: I'm building a .NET library (in C#) which gives full, optionally automated, simple, on-the-fly access to the compiler. The actual compiler access is done... However, building the complicated Remoting/AppDomain infrastructure is taking a while. Without this, there is no way to unload a runtime-compiled assembly before the main application ends. Is this final feature desirable and/or necessary for a good runtime compilation library? Thank you for your time, Eric Astor -
I'm looking for opinions here, so if the subject interests you, please reply. In the following post, runtime compilation is used to mean simple-to-use, on-the-fly access to the compiler, beyond
eval
statements, extending to the ability to compile full methods, classes, and assemblies. 1) Is runtime compilation worth the overhead (both in actual runtime cost and in time to implement/use)? 2) Is the ability to unload a previously loaded Assembly (possibly automatically, integrated into the garbage collector) important? 3) WARNING, Long Question: I'm building a .NET library (in C#) which gives full, optionally automated, simple, on-the-fly access to the compiler. The actual compiler access is done... However, building the complicated Remoting/AppDomain infrastructure is taking a while. Without this, there is no way to unload a runtime-compiled assembly before the main application ends. Is this final feature desirable and/or necessary for a good runtime compilation library? Thank you for your time, Eric AstorIt is now months since you posted this message. I hope you read this. Answers: 1) yes 2) not usually 3) no, not necessary. An interpreter you describe is very useful for testing. If that is the main purpose, memory leakage is not so important. Far more important is the user interface -- the command-line, or GUI. Regards, Frank Hileman
-
It is now months since you posted this message. I hope you read this. Answers: 1) yes 2) not usually 3) no, not necessary. An interpreter you describe is very useful for testing. If that is the main purpose, memory leakage is not so important. Far more important is the user interface -- the command-line, or GUI. Regards, Frank Hileman
I appreciate your answers to my questions. I had actually conceived of this library as a tool for self-modifying code or code read in from a database and then executed, as opposed to a testing tool (which would seem redundant, as access to this library merely gives access to the .NET compilers, already present when the .NET framework is installed). In such an environment, I believe that memory leakage would be likely to become an issue. I would appreciate if you would possibly re-answer the third question as below, taking this into account. 3) I'm building a .NET library (in C#) which gives full, optionally automated, simple, on-the-fly access to the compiler. The actual compiler access is done... However, building the complicated Remoting/AppDomain infrastructure is taking a while. Without this, there is no way to unload a runtime-compiled assembly before the main application ends. Is this final feature desirable and/or necessary for a good runtime compilation library? Thanks, Eric Astor
-
I appreciate your answers to my questions. I had actually conceived of this library as a tool for self-modifying code or code read in from a database and then executed, as opposed to a testing tool (which would seem redundant, as access to this library merely gives access to the .NET compilers, already present when the .NET framework is installed). In such an environment, I believe that memory leakage would be likely to become an issue. I would appreciate if you would possibly re-answer the third question as below, taking this into account. 3) I'm building a .NET library (in C#) which gives full, optionally automated, simple, on-the-fly access to the compiler. The actual compiler access is done... However, building the complicated Remoting/AppDomain infrastructure is taking a while. Without this, there is no way to unload a runtime-compiled assembly before the main application ends. Is this final feature desirable and/or necessary for a good runtime compilation library? Thanks, Eric Astor
The answer to 3) really depends on the usage of the solution. Your state the scenario, but there are not enough details in that scenario to answer the question. Why put the source in the DB? Why not compile and store the binary at the same time? What will the binaries be used for? Will the process using the binaries be long or short-lived (the most important question)? How often does the source change? If you just throw away the process then there is no need for an appdomain infrastructure. Even if you build one, you may still see memory growing. I believe even unloading an assembly still may cause memory leakage -- I seem to remember a problem in the vsa newsgroup, anyway. Perhaps it is the string cache (interned strings). If the only sure-fire way is to use a temp process, your solution is simplified -- you only need remoting. So you can look at the appdomain stuff as an optimization, and it may be you are optimizing something which does not need to be optimized. As I said, there is not enough info in your scenario to say exactly what is important. For myself, I was thinking of a .net interpreter. Mainly for testing. It is very useful to have an incrementaly constructed environment for testing. Sometimes you don't want to write a whole program to test one function. You want to type something on a command line or use a gui and have the function tested. NUnit etc. are nice, but they are really for automated testing. To test interactively you need an interpreter, that can create typed variables, and can pass the values of those vars to functions, using a commmand line or a gui. An interpreter, as I envision, would have to be able to do some run-time compiling, at least of expressions and functions. Command-line or gui variable assignments can be done with reflection, but expression evaluation must be very rich, as rich as a .net language, so you need a full-blown compile. If nobody does it I will do it someday. As I said, it is a time saver. In such an environment memory will be wasted (all the little dlls created each time a change is made to an expression). But it does not really matter. Regards, Frank Hileman
-
The answer to 3) really depends on the usage of the solution. Your state the scenario, but there are not enough details in that scenario to answer the question. Why put the source in the DB? Why not compile and store the binary at the same time? What will the binaries be used for? Will the process using the binaries be long or short-lived (the most important question)? How often does the source change? If you just throw away the process then there is no need for an appdomain infrastructure. Even if you build one, you may still see memory growing. I believe even unloading an assembly still may cause memory leakage -- I seem to remember a problem in the vsa newsgroup, anyway. Perhaps it is the string cache (interned strings). If the only sure-fire way is to use a temp process, your solution is simplified -- you only need remoting. So you can look at the appdomain stuff as an optimization, and it may be you are optimizing something which does not need to be optimized. As I said, there is not enough info in your scenario to say exactly what is important. For myself, I was thinking of a .net interpreter. Mainly for testing. It is very useful to have an incrementaly constructed environment for testing. Sometimes you don't want to write a whole program to test one function. You want to type something on a command line or use a gui and have the function tested. NUnit etc. are nice, but they are really for automated testing. To test interactively you need an interpreter, that can create typed variables, and can pass the values of those vars to functions, using a commmand line or a gui. An interpreter, as I envision, would have to be able to do some run-time compiling, at least of expressions and functions. Command-line or gui variable assignments can be done with reflection, but expression evaluation must be very rich, as rich as a .net language, so you need a full-blown compile. If nobody does it I will do it someday. As I said, it is a time saver. In such an environment memory will be wasted (all the little dlls created each time a change is made to an expression). But it does not really matter. Regards, Frank Hileman
Thank you for your points... I hadn't even thought of my runtime compilation component as a part of a logic-testing environment, and the features of a testing environment that you point out make the problem of memory leakage mostly irrelevant. Unfortunately, the points that you've made may not hold for my situation. The process (although not the thread) that requires code compilation in my solution should be rather long-lived, as it is a server in a centralized client-server architecture. However, thanks to your arguments, I've realized that an effective way to solve my problem is just to precompile each piece of code at startup of the server, then to access the compiled types. Although this may be expensive in terms of memory, it's much more efficient in terms of programming time required. I intend to polish my design of my existing Runtime Compiler interfaces slightly, then I'll use that. Once the entire server is finished, I'll probably write a CodeProject article on it... As this will be my first significant networking effort, aside from basic tests, the lessons that I learn may be useful to others working on other networking projects. Thank you for your points, Eric Astor
-
Thank you for your points... I hadn't even thought of my runtime compilation component as a part of a logic-testing environment, and the features of a testing environment that you point out make the problem of memory leakage mostly irrelevant. Unfortunately, the points that you've made may not hold for my situation. The process (although not the thread) that requires code compilation in my solution should be rather long-lived, as it is a server in a centralized client-server architecture. However, thanks to your arguments, I've realized that an effective way to solve my problem is just to precompile each piece of code at startup of the server, then to access the compiled types. Although this may be expensive in terms of memory, it's much more efficient in terms of programming time required. I intend to polish my design of my existing Runtime Compiler interfaces slightly, then I'll use that. Once the entire server is finished, I'll probably write a CodeProject article on it... As this will be my first significant networking effort, aside from basic tests, the lessons that I learn may be useful to others working on other networking projects. Thank you for your points, Eric Astor
Just curious about the "expensive in terms of memory" comment. In one of our apps, we are generating code dynamically and compiling it, at either design-time or run-time, according to the user's requirements. Noticing that the codedom compiler was simpler than vsa, and allows C#, we used that. I noticed that compilation occurs out-of-process, except for jscript.net, even if you specify in-memory. If you force the compile into another process (in the case of jscript) the overhead seems to be entirely in time and not memory. Unless I am missing something. We had to allow run-time code generation because the user's object hierarchy might be built at run-time. Normally, however, the hierarchy is built, code is generated and compiled, all at design-time. If you are curious, the app provides a way to graphically connect objects to realtime data sources, for process control and similar purposes. The compilation is needed for expression evaluation, and to avoid boxing during data transfer. Regards, Frank Hileman
-
Just curious about the "expensive in terms of memory" comment. In one of our apps, we are generating code dynamically and compiling it, at either design-time or run-time, according to the user's requirements. Noticing that the codedom compiler was simpler than vsa, and allows C#, we used that. I noticed that compilation occurs out-of-process, except for jscript.net, even if you specify in-memory. If you force the compile into another process (in the case of jscript) the overhead seems to be entirely in time and not memory. Unless I am missing something. We had to allow run-time code generation because the user's object hierarchy might be built at run-time. Normally, however, the hierarchy is built, code is generated and compiled, all at design-time. If you are curious, the app provides a way to graphically connect objects to realtime data sources, for process control and similar purposes. The compilation is needed for expression evaluation, and to avoid boxing during data transfer. Regards, Frank Hileman
True, compilation appears to work out-of-process... Except that once compilation is done, the CompilerResults object returned contains an Assembly object. The instant that the Assembly object is loaded into the process's memory (which can happen indirectly by loading the CompilerResults return value), the assembly (with all accompanying code and metainformation) is apparently irrevocably loaded into the process's AppDomain. This consumes memory. If I'm mistaken, please let me know.
-
True, compilation appears to work out-of-process... Except that once compilation is done, the CompilerResults object returned contains an Assembly object. The instant that the Assembly object is loaded into the process's memory (which can happen indirectly by loading the CompilerResults return value), the assembly (with all accompanying code and metainformation) is apparently irrevocably loaded into the process's AppDomain. This consumes memory. If I'm mistaken, please let me know.
I thought you were using the compiled types anyway, so I did not understand.