
By SmartBear Blog | Article Rating: |
|
September 22, 2016 12:00 PM EDT | Reads: |
1,399 |

Getting Real About Memory Leaks
By Matt Heusser
Modern programming languages tend to separate the programmer from memory management; Java programmers don't have to deal with pointers; they just declare variables and let the built-in garbage collector do its thing.
These garbage collectors are smart, but not perfect; they typically work by object reference. When all the references to an object go out of memory, that object can go out of memory too. Yet if two objects point to each other, they will always have a reference count, and never go away. That means the code written in Javascript to run in a browser, or Objective-C to run on a hand-held phone, or ASP to run on a server could very well have a memory leak.
When memory leaks happen on modern Operating Systems, the Operating System isn't going to throw an error. Instead, it will just use more and more memory, eventually going to virtual memory on the disk. When that happens, performance falls apart. People in operations reboot the server and that "seems to fix it"; users close and restart their browser, or reboot their phone.
Consider the Following Example
My first job in software was to create an electronic audit of a telecommunications bill. Some other software, maintained by my coworker Jeff, would read accounts, phones, and calls from a database and then create a text file that could be interpreted by a printer, called a post-script file. If we were smart, we'd have had written the tool in two parts, first to create a bunch of excel-like text files, then a second piece to combine those into bills.
One day, about four months in, the President of our 30-person software company came downstairs to my desk and said "Matt, I want you to take over the telecom bills", doing maintenance and new feature development.
The program was written in C. It read a list of accounts and looped through every account. Not every active account, every account, because an inactive account could still have an unpaid balance. We calculated the balance by adding up all the debits and credits through all time. If that amount added up to zero, we could skip the account. That was no big deal when we were helping a new, competitive regional carrier get started, with forty or fifty accounts and billing for five or six months.
The competitive carrier, however, was good at, well, competing. By the time I took over they had eighteen hundred accounts, and would be in the tens of thousands (and three states) before I left. Performance would become a real problem, but not for the reasons I expected.
The first two problems that hit us were a pointer out of range, then a memory leak.
Memory Out of Bounds
The software needed to store a great deal of data in memory for each account (the buildings, phones, calls, costs, and taxes) then spit it out to disk in post-script format. There are two basic ways to do this in C: Either allocate memory with pointers, which is hard to track, or simulate it using arrays. We didn't have objects, Test Driven Development wasn't really a thing, and I was inheriting code designed to support a very small customer base. What we did have was arrays. So to support two thousand calls, we could do something like this:
struct call {
char inOrOutbound;
datetimestamp timeStart;
datetimestamp timeEnd;
integer billedMinutes;
double cost;
}
char buildings [200][200];
char phones [200][200][1000][1000];
call calls [200][200][1000][1000];
What's represented here is up to 200 buildings per account, each of which can have 200 phones, each of which can have up to 1000 calls. The variable calls [5][10][25] would contain the fifth call for the tenth phone at the twenty fifth building. Actually, since C is zero-based, it would be the 6th call at the third phone at the eleventh building.
The software was basically a loop. For each account, for each building, for each phone, for each call. The calls needed to be sorted, then the results printed. Everything worked fine until in one run I got a memory out of bounds error. That's probably because the code was trying to access building 201, phone 201, or call 1001. The compiler has range checking built-in by default. To get around this, I moved the size of the data structure up as large as possible, which worked until we got an account that was too big for that.
Then I turned off range checking and declared a large amount of empty data structures, matching the originals in type, below the originals. That is an incredibly foolish thing to do, but it worked. Because the data structures were built into the compiled program (the ".exe file") and would be re-used for every account. Our little program would declare all the memory it needed one time, at the beginning, and use that.
Until we found the system slowing to a crawl on big accounts, like it was choking.
Enter The Memory Leaks
The data structures above are an over-simplification. We also needed to store the addresses of the building, the payments since the last bill, and so on. Like the examples above some of these were declared variables, put in the compiled code, "on the stack". Others were grabbed at run-time, using a C program call named "malloc" and its friend "free." Instead of declaring an array, we'd declare a character pointer, then malloc() some space at that pointer. When the function was done, we could free() the disk space.
If we remembered to do that.
As you've probably guessed, we had too many calls to malloc() and not enough to free(). That meant that memory use slowly crept up as we used the software. That's fine for fifty or even five hundred accounts; the memory use would go away when the program finished running. But, we started to get some very big accounts. I noticed that one big account would run, and performance would go down. The kicker, for me, was an out of memory error for our user. I went to Rich, the sysadmin, and asked for more memory for the user. He suggested I tune it instead. After carefully poring over the code, I found some mallocs() that weren't being freed. Adding the calls to free, the program did eventually finish. That account still took too long, but that's enough for today.
You might see how I struggled, but you might not see what that has to do with modern software delivery. Allow me to share just a bit more.
The Lesson for Today
These problems are silent killers, and fixing them is no longer as easy as searching through a program making sure every malloc() has a matching free().
If you write embedded medical software, or avionics, or anything in C, you are probably very familiar with these problems. If you don't, you might not be, but the problems are still there.
If your application degrades over time, the problem might just be memory leaks. The next logical question is how to find them.
Read the original blog entry...
Published September 22, 2016 Reads 1,399
Copyright © 2016 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By SmartBear Blog
As the leader in software quality tools for the connected world, SmartBear supports more than two million software professionals and over 25,000 organizations in 90 countries that use its products to build and deliver the world’s greatest applications. With today’s applications deploying on mobile, Web, desktop, Internet of Things (IoT) or even embedded computing platforms, the connected nature of these applications through public and private APIs presents a unique set of challenges for developers, testers and operations teams. SmartBear's software quality tools assist with code review, functional and load testing, API readiness as well as performance monitoring of these modern applications.
![]() Nov. 16, 2016 06:00 PM EST Reads: 1,377 |
By Liz McMillan ![]() Nov. 16, 2016 05:30 PM EST Reads: 709 |
By Liz McMillan ![]() Nov. 16, 2016 04:30 PM EST Reads: 102 |
By Elizabeth White ![]() Nov. 16, 2016 04:17 PM EST Reads: 214 |
By Liz McMillan ![]() Nov. 16, 2016 04:09 PM EST Reads: 242 |
By Elizabeth White ![]() Nov. 16, 2016 03:34 PM EST Reads: 113 |
By Pat Romanski ![]() Nov. 16, 2016 03:15 PM EST Reads: 602 |
By Carmen Gonzalez ![]() Nov. 16, 2016 03:00 PM EST Reads: 812 |
By Elizabeth White ![]() Nov. 16, 2016 02:30 PM EST Reads: 347 |
By Pat Romanski ![]() Nov. 16, 2016 02:26 PM EST Reads: 278 |
By Carmen Gonzalez ![]() Nov. 16, 2016 02:15 PM EST Reads: 600 |
By Liz McMillan ![]() Nov. 16, 2016 02:15 PM EST Reads: 1,185 |
By Elizabeth White ![]() Nov. 16, 2016 01:30 PM EST Reads: 242 |
By Liz McMillan ![]() Nov. 16, 2016 01:15 PM EST Reads: 353 |
By Elizabeth White ![]() Nov. 16, 2016 01:00 PM EST Reads: 594 |
By Elizabeth White ![]() Nov. 16, 2016 11:30 AM EST Reads: 663 |
By Liz McMillan ![]() Nov. 16, 2016 10:15 AM EST Reads: 568 |
By Liz McMillan ![]() Nov. 16, 2016 09:45 AM EST Reads: 1,246 |
By Pat Romanski ![]() Nov. 15, 2016 10:30 AM EST Reads: 1,135 |
By Liz McMillan ![]() Nov. 8, 2016 02:00 AM EST Reads: 469 |