16

in this example

procedure foobar;
var tab:array of integer;
begin
  setlength(tab,10);
end;

is the array destroyed or the memory is leaking?

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
Azarien
  • 201
  • 1
  • 2
  • 4
  • While it may not leak, you really should free your own variables. Do the SetLength(tab, 0); it's one extra line. If your worried about it then wrap it in a try/finally block. – Vivian Mills Jun 25 '10 at 02:42
  • 2
    I cannot endorse that advice, @Ryan. Do you manually clear all your string variables, too? When I see code assigning values to variables that are never used again, it tells me the programmer doesn't really understand how the language works. In particular, the compiler already puts a try-finally block around the function body to ensure that the dynamic-array variable gets cleaned up. Putting in one of your own is overkill. – Rob Kennedy Jun 25 '10 at 12:29
  • @Ryan, that's just wrong. The call to SetLength is a total waste, both of keystrokes and an unnecessary function call at runtime. Dynamic arrays are managed by the compiler, and will be freed automatically when they go out of scope. – Ken White Jun 25 '10 at 13:09
  • 2
    The memory for the array is freed by the compiler, but an array of objects that are referenced using a dynamic array must still be freed if that array "owns" them conceptually. Change the above code from "tab:array of integer" to "tab:array of TObject" and suddenly you have a leak possibility. – Warren P Jun 25 '10 at 13:58
  • @Rob, So are you saying is that it's a waste of time to do any kind of defensive coding or only for the given example? I would prefer to have, as you put it, overkill and ensure that I know what's going on than to make an assumption and turn out to be wrong. After reading your comment I went to find out what is the proper way to handle it and using a SetLength of 0 may not be the best solution, but according to the help file you should either assign nil or us the Finalize function. – Vivian Mills Jun 25 '10 at 15:45
  • @Ken, Are you also not advocating defensive programming? So it's an extra call, big deal. Assigning Nil or calling Finalize, as recommended by the Help is still going above and beyond what your advocating. As Warren P pointed out what if the example above wasn't an array of int but an array of objects? All I'm saying is that you should clean up after yourself so that you know exactly whats going on regardless of what the exact code looks like. – Vivian Mills Jun 25 '10 at 15:48
  • 1
    @Ryan, assigning nil, calling Finalize, and setting the length to zero are all equivalent ways of releasing a dynamic array. And they're *all* unnecessary when the array's going out of scope because that's yet another way to release a dynamic array. The help doesn't say so explicitly because it's implied by stating the dynamic arrays use the same reference-counting technique that long strings use. Defensive programming is fine, but it's better when you're defending against things that might actually happen. – Rob Kennedy Jun 25 '10 at 16:24
  • @Ryan, Warren's comment is irrelevant. Allowing the array to be destroyed as it goes out of scope won't free the objects, but neither will manually clearing or finalizing the array. No matter what an array's element type is, the rules for how the array gets destroyed do not change; in fact, the compiler even generates identical code (save for the PTypeInfo value it passes to DynArrayClear). – Rob Kennedy Jun 25 '10 at 16:31

2 Answers2

16

The memory is freed. (That is, no memory leak!)

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • 4
    Elements are also freed if those are managed by the compiler too (dyn arrays, strings, intf, records with such types and so on). – alex Jun 24 '10 at 20:53
  • 2
    For "tab:array of Integer", everything is freed. For "tab:array of TObject", or any other class, you must free the Objects yourself. – Warren P Jun 25 '10 at 13:57
  • True, @Warren, but that has nothing to do with the array. The same advice applies to an ordinary scalar. Objects need to be freed; integers don't. – Rob Kennedy Jun 25 '10 at 16:34
1

The array is automatically freed, but I've seen obscure cases where it isn't for some reason. I solved it by setting the array to nil.

Alan Clark
  • 2,017
  • 21
  • 28
  • 6
    There are only two reasons why it wouldn't be freed. Either you're doing something scary with pointers that messes up the reference counting, or the array is owned by an object or record which is also leaking. – Mason Wheeler Jun 24 '10 at 20:06
  • I know, somehow there was something else causing it not to auto-free. I wish I still had the example to prove it! But I don't. – Alan Clark Jun 25 '10 at 03:59
  • That would be a bug in the compiler's code-gen. Or maybe it was a threadvar? The help clearly state that managed type used as threadvars won't free themselves automatically and you need to do so manually. – Ken Bourassa Jun 25 '10 at 12:41
  • It wasn't a threadvar, I've never used them. It was just an array of doubles that was a field of a class, FastMM revealed the leak. It was in Delphi 7. – Alan Clark Jun 25 '10 at 19:50