03.10.2014, 00:13 | #1 |
Участник
|
mfp: Garbage Collection and RPC calls in X++
Источник: http://blogs.msdn.com/b/mfp/archive/...alls-in-x.aspx
============== Dynamics AX is a 3-tier application that evolved from a 2-tier application. Yes, this is right, the first versions of Axapta was solely a client side application communicating with the database. In version 2.0 the middle tier was introduced. The X++ language got a few new keywords, client and server, and the AX run-time provided the smartest marshaling of objects across the tiers on the planet. The marshaling is guaranteed to work in virtually any object graph you can instantiate. You can have client-side classes holding references to instances of server-side classes, which contains references back to other client-side objects, which references … you get the idea. All you have to do as a developer is to decorate your classes as client, server or called-from. You don’t have to worry about any low level details about how the instances are communicating across the wire. The key word in the previous sentence is “have” – stuff will just work, but unless you are very careful you may end up creating an extremely chatty (i.e. lot of RPC calls on the wire) implementation. Recently I’ve seen two cases of well-intended changes that on the surface looked right, but both caused an explosion of RPC calls. Both were implemented by smart guys, and I wanted to point them to an article explaining the problem – and I realized that article didn’t exist. Until now. Garbage collection in AX The garbage collector (GC) AX is responsible for releasing memory consumed by object instances no longer in use. In .NET the GC is indeterministic, it runs when it “feels like” running, typically when the system has CPU capacity and is low on memory. In contrast the GC in AX is deterministic – it runs every time an object goes out of scope. Consider this small example: static void GCJob1(Args _args){ MyServerClass myServerClass; //Create instance myServerClass = new MyServerClass(); //Release instance}Jobs run on the client tier, so this will create an instance of the MyServerClass and release it again. MyServerClass is a trivial class with RunOn=Server. If we enable Client/Server trace under Tools | Options | Development, and run the job, we get: Create instance Call Server: object: MyServerClass.new() Release instance Call Server: destruct class Notice this: The client-tier reference to the server instance, is keeping the instance alive. When the reference goes out-of-scope, then the GC takes over and calls the server to free the server memory. Island detection The GC is not just looking for instances without references – often object graphs are more complicated. To release memory that is no longer needed, the GC is looking for groups of objects without any external references – or in popular lingo: Islands. This search is potentially harmful to the performance of your application. The GC must traverse all members of any object that goes out of scope – regardless of their tier. Let’s build out the example by introducing a client side class that is referenced by the server instance. static void GCJob2(Args _args){ MyServerClass myServerClass; MyClientClass myClientClass; //Create client instance myClientClass = new MyClientClass(); //Create server instance myServerClass = new MyServerClass(); //Make server instance reference client instance myServerClass.parmMyClientClass(myClientClass); //Release instances}Now; when myServerClass goes out-of-scope then the GC will start analyzing the object graph, and it will discover an island consisting of our two objects – despite they are on different tiers, and it will release the memory consumed. Pretty smart – but not for free! This is the resulting RPC traffic from the above job: Create client instance Create server instance Call Server: object: MyServerClass.new() Make server instance reference client instance Call Server: object: MyServerClass.parmMyClientClass() Call Client: set class loop dependencies Call Client: test class loop dependencies Release instances Call Server: destruct class Call Client: destruct class Now suddenly we jumped from 2 RPC calls to 6! What happened? We met the GC!
A real life example Consider a server side class that is looping over some data, and for each, say, row, it spins up another class instance on the server to do some calculations. This is all server side, and perfect. So let’s add client-side member to the mix. class MyServerClass{ MyClientClass myClientClass; public void run() { int i; MyServerHelper myServerHelper; //Create client-side member myClientClass = new MyClientClass(); //Loop over some data for (i=1; i
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору. |
|