Re: Memory management clarification



Maciej Sobczak <no.spam@xxxxxxxxxxx> writes:

> Robert A Duff wrote:
> > If you put "for T'Storage_Size use 1_000_000;", then implementations
> > should reclaim all memory allocated for type T when the scope of T is
> > left.
>
> Nice. Why putting this arbitrary limit?

You can put any limit you like. It does not need to be known at compile
time.

Note that this feature is inherited from Ada 83. It is subsumed by
storage pools (added in Ada 95).

> And what does it mean, anyway - is the pool actually pre-allocated with
> this size when the for..use... statement is executed, or does it start
> empty and later "inflates" as necessary, but no bigger than the given
> limit?
> The difference is not only the observable memory consumption (even when
> not the whole pool is used), but also the possibility and timing of
> low-memory errors.

It means approximately 1_000_000 storage units are *reserved* for this
type. You are guaranteed to be able to allocate (approx) that much.
One possible implementation is to allocate that space on the stack of
the current procedure, and allocate the heap objects within that.
Then it gets automatically freed when the procedure returns.

But the implementation is not required to consume the memory -- for
example, it can allocate *virtual* address space, but not physical
memory or swap space.

The timing of out-of-memory errors (Storage_Error exception) is a
problem anyway -- according to the standard, you can get Storage_Error
at any time.

If you don't like the "reserve arbitrary limit" semantics, you can write
your own storage pool type that has whatever semantics you like. For
example, reserve nothing, but still deallocate on procedure return.
The Finalize of the storage pool type comes in handy for that.

> > This is not
> > a very useful capability, because most access types need to be at
> > library level, so the memory won't be reclaimed until the whole program
> > is done.
>
> Indeed, not really useful.
>
> > You should look up user defined storage pools. You can say:
> > for T'Storage_Pool use My_Pool;
> > and then you can control when memory will be reclaimed.
> > You can reclaim all memory in My_Pool whenever you like -- but
> > beware dangling pointers.
>
> I have to beware them when using Unchecked_Deallocation as well. :)

Indeed. ;-)

> >>2.
> >>
> >>loop
> >> declare
> >> X : MyTypeRef;
> >> begin
> >> X := new MyType;
> >> end;
> >>end loop;
> >>
> >>What now? Is this any different from the memory management point of view?
> > No. X.all will never be reclaimed (on most implementations). The only
> > difference here is that you're allocating only one object.
>
> Not really - there's a loop.
> I understand that the code above leaks memory, just like my first example.

Yes, both leak memory. The loop probably leaks faster. ;-)

> > Suppose we added a call P(X) inside the begin/end. And suppose P saves
> > X in a global variable. The implementation cannot deallocate the memory
> > X points to, because that would leave a dangling pointer in the global
> > variable.
>
> Right, but I was interested exactly in the case where there is just one
> reference and it is trivial for the compiler to prove that the object is
> not aliased.

I don't know of any compiler that does this trivial proof.
It's such a special case that it wouldn't be all that useful anyway.

>... But without GC there's no difference anyway.
>
>
> >>4.
> >>
> >>Is it possible to associate some function with object allocated by new,
> >>which would be called at the time (or maybe after) the object is
> >>reclaimed?
> >>Yes, I'm asking about destructors or finalizers.
> > Yes. Look up "controlled types". These allow you to associate a
> > Finalize operation with a type. For local variables, Finalize will be
> > automatically called when the procedure is left.
>
> Good - this, basically, should allow me to implement some form of local
> resource manager (in C++ this idiom is called RAII) that will deallocate
> the object (or any other resource) when the scope is left.

Right -- it's pretty much the same as in C++.

> > For heap objects,
> > Finalize will be called when you do Unchecked_Deallocation (or, if you
> > never do U_D, when the program is done).
>
> Fine. Is the order of calling finalizers well-defined for the latter case?

I don't remember the exact rules. The order is somewhat left up to the
implementation, but you'd have to read the RM to understand the details.

> Thank you for these explanations,

You're welcome.

- Bob
.



Relevant Pages

  • Re: Is there a maximum contiguous memory allocation?
    ... but could ALLOCATE it! ... allocate it if I had 2GB of physical memory! ... the amount of physical memory I have installed. ... Note that you can use raw VirtualAlloc to improve your ...
    (microsoft.public.vc.mfc)
  • Tru64 issues with Infinite limits
    ... An automated test in my nightly build was failing due to Out of Memory ... Cannot allocate block 146 ...
    (comp.unix.tru64)
  • A question about memory reclaim
    ... A guy told me Linux can reclaim the allocated memory of process ... He said even a process uses malloc or new to allocate ... child thread exits but the main thread is still running which means ...
    (comp.os.linux.misc)
  • Re: run-time vs compile-time
    ... > offset related to some location (like stack base) somewhere. ... > offset from heap to pi. ... When you allocate an int on the heap, it is allocated at address 1. ... application has a given amount of memory it can use as it wishes. ...
    (alt.comp.lang.learn.c-cpp)
  • Re: run-time vs compile-time
    ... > offset related to some location (like stack base) somewhere. ... > offset from heap to pi. ... When you allocate an int on the heap, it is allocated at address 1. ... application has a given amount of memory it can use as it wishes. ...
    (comp.lang.cpp)