Products



Stay in touch

Add your e-mail address here to receive the monthly TMS Software alerts.


    

Content:
Product releases
Product articles
Technical articles
Website changes
Software development

Products:

<< >>
July 2014



Monday, June 02, 2014

Finding memory leaks in Delphi for iOS

Introduction

Delphi has a very high degree of compatibility between desktop and mobile code: with some little differences, code written for Win32 will run fine in iOS and Android.

Many of those differences are in strings, like not having UTF8 strings (which I hope they'll finally see the light and re-add some day), or having zero-based strings instead of 1-based (which if you are writing code for both mobile and desktop, and you are not into self infringed pain, you'll just want to make all strings 1-based by writing {$ZEROBASEDSTRINGS OFF} everywhere in your units).

But on this post I wanted to focus in what is probably the biggest difference between Delphi mobile and Delphi desktop: Automatic Reference Counting (ARC). As you will probably know, ARC is a "light" kind of garbage collection which works by keeping the number of objects which have a reference to another object. When the reference count drops to 0 (nobody is using the object), it is automatically destroyed. Most of the time ARC works fine and allows you to replace of thousands of lines like:

  Whatever := TWhatever.Create;
  try
     DoSomething(Whatever);
  finally
     Whatever.Free;
   end;

by simply
  DoSomething(TWhatever.Create);

Delphi will take care of destroying whatever for you when it is not used anymore, and generally this is a good thing (™), since in most cases the more work the compiler does for you the better. The compiler will never forget to free an object. But ARC comes with some disadvantages too: Not only it will be slower since it has to increase and decrease the reference counting of the objects in a thread safe way (most likely involving locks), but even worse, code that runs without leaks in "Classic Delphi" might start to leak when compiled with ARC.. This is a very serious problem, because it won't manifest itself immediately. The converted desktop code will work fine in mobile, but under the hood memory usage will grow continually until the app crashes because it runs out of memory. So we need a way to catch and fix those memory leaks.

ARC and Circular References

The problem with ARC is simple: Classes that directly or indirectly reference themselves (think in double linked lists, or any cache scheme where the main objects keep a reference to the cache, and the cache to the main object). In those cases you have a situation like the following:


"Parent" has 2 references (one from the root object which created it, the other from the child). Child has 1 reference from the parent. When we exit the method, "Parent" reference count will drop to 1 and child reference count will stay at 1 too. Neither parent or child will be destroyed, and they will leave forever happily ever after: each one of them keeping the other alive.

And note that even if you explicitly call Parent.Free, it still won't be destroyed. In ARC, Free just sets the object to nil, breaking the reference from Root to Parent and decreasing the reference count to 1, but the reference from the child will still be there, keeping the Parent alive. You would have to call Parent.DisposeOf to explicitly call the parent destructor, and in the parent destructor set Child to nil. Code that used to run fine in Desktop (where you call Parent.Free) stops working when you use it in ARC. And this is a problem. For this particular case, ARC not only didn't remove any existing leak, but it introduced one.

So how do we fix it?Delphi has a [WEAK] attribute that you can use to "break" those reference loops. By marking the child reference as weak, it won't count towards the parent's reference count.



With the [weak] reference now parent reference count will be 1 and not 2, and when the reference from root is broken, parent and child will be destroyed. And this should be enough theory for now: time to get our hands dirty with some real code.

Creating the memory leak

Let's start with two simple classes that reference themselves:
type
TChild = class;

TParent = class
  public
  FChild: TChild;
  constructor Create;
  destructor Destroy; override;
end;

TChild = class
  public
  FParent: TParent;
  constructor Create(const aParent: TParent);
  destructor Destroy; override;
end;

The classes do just the bare minimum: When you create a TParent it will create and keep a reference to a TChild, and the Child will keep a reference to its parent. Just to know when those classes are being destroyed, we'll add messages in the destructor:
{ TParent }

constructor TParent.Create;
begin
  FChild := TChild.Create(self);
end;

destructor TParent.Destroy;
begin
  ShowMessage('Parent destroyed!');
  inherited;
end;

{ TChild }

constructor TChild.Create(const aParent: TParent);
begin
  FParent := aParent;
end;

destructor TChild.Destroy;
begin
  ShowMessage('Child destroyed!');
  inherited;
end;
And finally, let's add a button on the form, and create an instance of the parent class:
procedure TForm1.Button1Click(Sender: TObject);
var
  Parent: TParent;
begin
  Parent := TParent.Create;
end;
Let's try and run the application. Launch it and press the button. If everything goes as expected, no message "Parent destroyed!" or "Child destroyed!" should appear. Even when we have ARC, Parent and Children aren't being destroyed.

If we aren't fully convinced yet, one way to verify it is to place a breakpoint under the Parent := TParent.Create line, and look at the reference count of the object:


As you can see, refcount is 2: One for the "Parent" variable and the other from the child. When we exit the method, refcount will go down to 1, but it will never be 0 and the object will never be destroyed.

So now the question is: How can we find leaks in a big project? We can't go logging all destructors and we can't check all the refcounts of all the objects. When writing Win32/Win64 code, we have an invaluable tool: FASTMM. Either by writing ReportMemoryLeaksOnShutdown := True; in your app startup code, or by using the full FASTMM debug options, you can easily find the objects that have leaked in your app.

But there is no FASTMM for iOS; iOS memory allocations requests go directly to the iOS memory allocator. One idea could be to target "Win32" for our mobile application and try to use our Win32 leak detection techniques there:



But alas, the "Win32" target doesn't have ARC, so no objects will be destroyed at all. We'll have to try a different approach: We'll try the native OSX tools instead. XCode comes with a very helpful tool not so helpfully named "Instruments", which can be used to profile and look at leaks in objective-C apps. Given that Delphi in OSX uses the same LLVM backend and Debug information as XCode, it would be expected that we can use the same tools as in XCode. And it turns out we can.

Finding the leak

First steps first, we'll start by launching Instruments. You can do it by launching XCode, then go to Menu->XCode->Open Developer Tool->Instruments:



Of course, once it opens you might want to keep it in the dock to be able to open it faster next time. While in this post we will be only showing how to find memory leaks, Instruments is a very powerful tool which includes a CPU profiler, memory diagnostics, I/O activity and much more. If you are doing serious iOS work, you are likely to spend a lot of time in Instruments.

You should be greeted by a screen similar to this one:



From here, we will select "iOS" at the left (Leak detection won't work in the iOS simulator), and then "Leaks" at the right. Once in the main Instruments screen, we need to choose the app to profile. We'll select the iOS device (again, leak detection won't work in the simulator) and then select our app from the "Choose target" menu inside the "Choose target" combobox:



In the short video below, I'll show how profiling the app looks like. I've marked some interesting parts on it:

1) Choose a target. This is where we select the app that we have previously deployed to the device. Make sure to deploy it in DEBUG mode so symbols are loaded.

2) Record. When we press "Record" the app starts in the device, and the profiler starts running. At first the "Allocations" profiler is selected, and while it has a lot of interesting information on its own, for this article we are interested in the leaks. So we select "Leaks" from the left sidebar.

3) Snapshot. On the lower left pane, we have the "Snapshots" section. By default it takes a memory snapshot every 10 seconds, but we can select the interval or manually trigger one. In this video we pressed the button on the device, then pressed the "Snapshot Now" button in Instruments, and a memory leak is shown. After that we pressed the button twice more, and then "Snapshot Now" again. You can see the leak count increases to 3. You can also see the red bars in timeline showing when the leaks where created.

4) Inspect the call stack. By pressing the button to show the right pane in Instruments, we can take a look at the stack trace that lead to the leak. You can see that even when this is a delphi app, the debug information is all there, and you can see the actual delphi class names like "TParent", and the method names like "Button1Click". This makes it really easy to pinpoint the troubling parts.

5)Inspect the cycles. Finally, we can also look at a view that is helpful to see the cycles. In this case the cycles are very simple so the diagram doesn't add much, but in a more complex case this can also help finding the element that is leaking.



Fixing the code

Now that we have find the offending code, the last step is to fix it. To do that, just add a [WEAK] attribute to the child reference to the parent.

The child class will end up as follows:

TChild = class
  public
  [Weak]FParent: TParent;
  constructor Create(const aParent: TParent);
  destructor Destroy; override;
end;


If we run the application now, we should finally be able to see the messages in the destructor:



And Instruments should show no cycles or leaks. Also if you debug the application and inspect the reference count for parent, it should never be 2.
Ok, I think this should be it. Have a happy leak hunting, and don't forget to explore the other "Instruments" available in "Instruments" like the allocation or cpu profilers. Most instruments work just fine with Delphi apps, and there are a couple of jewels waiting for you on there.

Bookmarks: 

Adrian Gallero




This blog post has received 1 comment. Add a comment.



Monday, April 14, 2014

The story of a teenage scripter

Last week I was just browsing the TMS site, looking at the version numbers of existing products, when I saw TMS Scripter current version: 6.3. I see those numbers often and I’m used to them, but this time, I was a little bit shocked. Just like a father whose son is born and, in the blink of an eye, watches this son going to college in his eighteen, I was astonished to see how far TMS Scripter went, and for so long. It’s true that my oldest son is just about to turn 5 years-old, but for that my eyes didn’t even have to blink – they were wide open – so I can imagine how it might be for a father of a grown-up son. My second son is only 12 days old, and got me so worried last week to the point I went to the gym with a different tennis shoe in each foot and only noticed it when I came back home. I’m trying not to blink an eye. But I digress.

Thing is TMS Scripter is already a teenager. I have to face it. First version was released in 2001, but it was being already used in internal projects for at least three years. It’s interesting to see old family pictures, and the following one shows version 1.5 from November, 2001, when it was still called TatPascalScripter and had just a new featured added: COM interfaces support.



Since then, it had fourty-six – fourty-six! – releases, which added the following main features (in chronological order) that transformed TMS Scripter over the years:

  • Support for COM Interfaces
  • Basic Syntax
  • Delphi classes import tool
  • Debugger
  • Syntax highlight memo with breakpoints, etc.
  • Events support
  • Code completion
  • WebScripter
  • Watches
  • Thread support
  • Script-based libraries
  • DLL importing from script
  • Source explorer
  • Script-based forms
  • Complete IDE with form designer and object inspector
  • Automatic class import using new RTTI
  • Parameter hints
  • Script-based classes
  • Undo/Redo in form designer
  • Windows 64-bit support
  • Firemonkey Forms
  • Mac OS support


Besides, of course, constant language improvements, introduced over the releases, and support to all the new Delphi versions released, until the latest one, XE6, with no exception.

Over all those years and versions, full backward compatibility was kept, regression bugs were minimized and fixed, and I believe most of TMS Scripter users had a safe and peaceful life like, with full support and compatibility – including the famous migration from ANSI to UNICODE.

But what brings more satisfaction is to see the different way TMS Scripter affects many users. Yes, TMS customers are overall satisfied, enjoy the high number of features in our products, and appreciate the support we provide. But TMS Scripter is, of the products I manage, the one that receives more “emotional” comments. Users mention to be surprised every day with it, and comment how it constantly opens new doors in their applications. I believe one of the reasons for that is the fact that TMS Scripter is an “open” product, with so many different ways to use and applications, that it often requires (and allows) a great amount of creativity from its users, making them a kind of “artist” of their own software.

Yes, TMS Scripter is already a teenager. But more exciting things will come and its story doesn’t end here.


Bookmarks: 

Wagner Landgraf




This blog post has received 2 comments. Add a comment.



Monday, April 07, 2014

Hello, TMS Sparkle

TMS Sparkle is a brand new product released by TMS Software. It is a Delphi framework for network, Internet programming.

As stated in the online documentation, TMS Sparkle is the core building block for several other TMS products and technologies, such as upcoming TMS RemoteDB and TMS XData. Such products needed to be built from scratch, and to rely on a robust framework for which TMS could have 100% control and also responsibility. For such products to work flawlessly, we needed to be sure to build such products in a framework that must be properly tested, and have fast response in performance improvement and bug fixing.

It is trustworthy, fresh, modern, cross-platform (Windows, Mac, iOS, Android) and most of it, as much platform native as it can be.

TMS Sparkle is part of TMS Business Subscription, which contains many other products, like TMS Aurelius and TMS Scripter, and will also receive the mentioned upcoming products TMS RemoteDB and TMS XData.

For detailed information you can refer to TMS Sparkle product page and online documentation. In the meanwhile, to illustrate its usage, here is the full source code for a minimal Http Server using TMS Sparkle:

program HelloWorldServer;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  Sparkle.HttpServer.Context,
  Sparkle.HttpServer.Module,
  Sparkle.HttpSys.Server;

type
  THelloWorldModule = class(THttpServerModule)
    public procedure ProcessRequest(const C: THttpServerContext); override;
  end;

procedure THelloWorldModule.ProcessRequest(const C: THttpServerContext);
begin
  C.Response.StatusCode := 200;
  C.Response.ContentType := 'text/plain';
  C.Response.Close(TEncoding.UTF8.GetBytes('Hello, World!'));
end;

const
  ServerUrl = 'http://localhost:2001/tms/business/hello';
var
  Server: THttpSysServer;
begin
  Server := THttpSysServer.Create;
  try
    Server.AddModule(THelloWorldModule.Create(ServerUrl));
    Server.Start;
    WriteLn('Hello World Server started at ' + ServerUrl);
    WriteLn('Press Enter to stop');
    ReadLn;
  finally
    Server.Free;
  end;
end.



Bookmarks: 

Wagner Landgraf




This blog post has received 2 comments. Add a comment.



Thursday, February 06, 2014

Get device independent, put your settings in the iCloud

On the road, we carry a smartphone, in a couch we grab the tablet and in the office we sit behind the desk and use a desktop computer. In all scenarios though, we want to use applications that give us access to the same data and functions. Therefore, it is also logical that when we change our parameters for access to this data and functions via the desktop machine application, these same parameters and settings will be reflected (automatically) when we use the smartphone or tablet specific application and vice versa. In the Apple world, the answer to this scenario is persisting our parameters / settings on the iCloud.

As a Delphi developer, we typically like it when we can persist this information with a minimum amount of code so we can focus on the business logic instead of all technical complexities of using the iCloud. Delivering this promise, we've now released two new non-visual components: TTMSFMXNativeiCloud and TTMSFMXNativeMaciCloud. With these components, putting key/value pairs on the iCloud and retrieving them becomes as simple as using a method
 procedure AddKey(AKeyName: String; AKeyValue: TValue);
to create a key/value pair and using the property:
 
 property KeyValues[AKeyName: String]: TValue
to get and set the value of the key.

So, when in one application, the user would change a setting, this can be done with:
var
  FName: strring;

FName := 'TMS';
TMSFMXNativeiCloud.KeyValues['MyAmount'] := 1234;
TMSFMXNativeiCloud.KeyValues['MyName'] := FName;
Thanks to the magic of the iCloud and these non-visual components, the key/value pairs will now automagically be synchronised between applications on different devices coupled to the same iCloud account. If the app wants to react immediately to iCloud pushed value changes, the event TTMSFMXNativeiCloud.OnKeyUpdate is triggered and can be handled like:
procedure TMSFMXNativeiCloud.KeyUpdate(Sender: TObject; AKeyName: String; APreviousValue, ACurrentValue: TValue);
begin
   if (AKeyName = 'MyName') then
     FName := ACurrentValue;
end;
Note that the value is of the type TValue and supports strings, booleans, integers, double and a TMemoryStream. Of course, the component offers several more options like deleting a key/value pair, programmatically forcing a synchronisation of the values on the iCloud, receiving events when iCloud pushed updates to values etc...

TTMSFMXNativeiCloud is available now in the newest TMS iCL update and TTMSFMXNativeMaciCloud is available now in the newest TMS mCL. A FireMonkey iOS demo in TMS iCL and a FireMonkey Mac OS-X demo in TMS mCL demonstrate this concept by having a customizable set of key/value pairs shared via the iCloud between these applications as shown in the screenshot above.

Bookmarks: 

Bruno Fierens




This blog post has not received any comments yet. Add a comment.



Sunday, January 05, 2014

The year 2013 at TMS

When you go home in the evening after working hard all day, do you also often have the feeling you have achieved much less than you had expected or hoped for that day? If so, join the club.
But now that I sit back at the start of a new year and retrospectively look at what 2013 brought for TMS, I hope you'll agree with me that we nevertheless achieved quite a lot. Actually, 2013 was quite a rollercoaster.

To start with, our VCL development continued relentlessly.

TMS Component Pack
We have seen 4 major releases, going from v6.7.0.0 to v7.1.6.0. with support for RAD Studio XE4 and XE5 added but also with 7 new components, 206 new features and numerous improvements added. For 2014, new components & new features are already in development. Be in touch with our development team to express your desires & comments so we can integrate these also in future updates.

TMS Aurelius
Our flagship ORM for Delphi, TMS Aurelius continued to be highly appreciated by customers and several exciting capabilities were added. There is now integrated database schema update and validation. There is iOS support with full native access to SQLite. There is the new TExpression/TLinq for stronger querying capabilities. TMS Aurelius is also being readied for seamless integration with TMS XData that will be released in 2014.

TMS Cloud Pack
This was another rapidly growing product in 2013. TMS Cloud Pack now comprises seamless access to the worlds most popular cloud services like Twitter, Facebook, LinkedIn, FourSquare, iCloud Calendar, iCloud Contacts, Google Calendar, Google Contacts, Live Calendar, Live Contacts, Flickr, Picasa, Instagram, Google Drive, SkyDrive, DropBox, Box.NET and more... But this is only the start. Watch 2014 for some exciting new capabilities to be added.

GEO mapping components TWebGMaps and TWebOSMaps
In 2013, we extended our component for Google Maps, TWebGMaps with directions, directionlist, waypoints and also introduced a new component TWebOSMaps that offers similar functionality but using Open Street Maps. We also made our GEO mapping components available for web application development with an IntraWeb version and for mobile development.

TMS Advanced Chart
This year also saw some major new features added in TMS Advanced Charts. 3D pie charts and the funnel chart type were added along with several smaller enhancements that make the every day programming with TMS charts easier.

With the releases of RAD Studio XE4 and XE5 this year, bringing us cross platform development targetting iOS and Android, there was without a doubt also much activity at TMS in the area of FireMonkey development!

TMS Flexcel
The strongest VCL solution on the market for native XLS/XLSX file manipulation with included PDF & HTML report generation on Windows, TMS Flexcel now makes its power also available for Mac OS-X, iOS and Android. No matter what operating system you target, TMS Flexcel offers a versatile, feature rich and high performance solution for dealing with XLS, XLSX, XLSM files.

TMS Pack for FireMonkey
With RAD Studio XE4 and XE5 bringing native iOS and Android support, it is evident that our team had its hands full with ensuring TMS Pack for FireMonkey components work flawlessly on all four platforms and on top of that we added new components and numerous new features. There is a new syntax highlighting memo in the TMS Pack for FireMoney, the included feature-rich grid was extended with new functions and improvements, a VCL listview interface compatible wrapper was added, live bindings support was added in the TTMSFMXTileList and support for it was improved in several components.

TMS Cloud Pack for FireMonkey
TMS Cloud Pack for FireMonkey is a new product that saw the light in 2013. Developers can now easily integrate the consumption of popular cloud services from Delphi iOS or Android applications via ready to use Delphi classes that wrap all the functionality. TMS Cloud Pack for FireMonkey development is closely tied to TMS Cloud Pack for VCL development, so expect new features and improvements to become available in both.

In 2013, we also saw the creation of a new category of components: the 100% native iOS and Mac OS-X components. For those instances where it is really needed to get the maximum performance and maximum UI look & feel consistence out of your applications, we created TMS iCL targetting iOS and TMS mCL targetting Mac OS-X. TMS iCL and TMS mCL bring more than just thin Delphi class wrappers around iOS or Mac OS-X APIs. Our focus is on easy to use, feature-rich Delphi components designed with RAD in mind.

TMS iCL
This suite of components targets iOS. It contains nearly all native iOS UI components like buttons, edit, switch, pickers etc... but also rich Delphi classes giving access to complex iOS controls such as the collectionview, rich text editor, tableview, mapview, toolbar etc... For 2014, we have several new components in research and development that go far beyond simple iOS API wrapping.

TMS mCL
Similar to TMS iCL, TMS mCL targets Mac OS-X. This component set is designed with the same philosophy as TMS iCL. Also here, there is a rich text editor, a tableview, toolbar, PDF viewer, web browser and much more.

Not only for Delphi developers we added a huge array of components for cross-platform / mobile application development, also in the area of .NET, TMS Flexcel for .NET entered in the mobile area with new support for Xamarin. Via Xamarin, TMS Flexcel .NET now also targets iOS and Android!

In the area of web development, the focus was on new products like TMS IntraWeb WebGMaps, TMS IntraWeb WebOSMaps, TMS IntraWeb Cloud Pack as well as continuously improving our products for cross browser compatibility and adding support for the latest versions of IntraWeb 12.2 and IntraWeb 14.0. For this year, we have some exciting new developments underway for your web development.

Of course, this list is just a summary of some major component developments that happened here in 2013 at TMS. It would make this article far too long to list everything in detail. Check the version history tab on each product page to have a look at what was recently added! Other than component development, in 2013 we had several other major events. One such event was the first TMS developer day we organized with the support of the Be-Delphi organisation in April. From the feeedback of attendees, it was clear this day was very much appreciated and we plan a new TMS developer day this year but most likely at a different location. The second major event this year was the release of our completely restyled website. And finally, we have also introduced feature-request voting this year. With this tool, we cannot only capture what you would like to see us develop but also measure interest and steer our development to what you need most. Since its introduction this year, we have already handled more than 20 such requests.

So, we hope you'll agree with us that 2013 was quite an exciting year. Our batteries are recharged to bring more excitement for 2014. Our team is ready to listen and respond to all your inputs, feedback, comments, questions and suggestions to create together great software development solutions.

Bookmarks: 

Bruno Fierens




This blog post has received 3 comments. Add a comment.




Previous  |  Next  |  Index


Copyright © 1995 - 2014 TMS Software v4.0