Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

DEALLOCATING DATA TYPE POINTERS

ScottBoyce
Beginner
2,402 Views

Just a general coding question regarding data type pointer variables.

My question is for pointer data types that contain allocatable arrays such as the following example:

[fortran]

C DATA TYPE DECLARATION IN A MODULE

      TYPE TARRAY
        INTEGER::POS
        LOGICAL::USEVAL
        DOUBLE PRECISION::VAL
        DOUBLE PRECISION,DIMENSION(:),ALLOCATABLE::TIM,DAT
      END TYPE 
      !
      TYPE TTYPE
        INTEGER::NT
        CHARACTER(20), DIMENSION(:),ALLOCATABLE::NAM
        TYPE(TARRAY),DIMENSION(:),ALLOCATABLE::T
      END TYPE
      !
      TYPE, EXTENDS (TTYPE):: TTYPEAUX
        REAL,         DIMENSION(:),ALLOCATABLE:: FAC
        INTEGER,      DIMENSION(:),ALLOCATABLE:: IDX 
        LOGICAL                               :: PRNT
      END TYPE

 

[/fortran]

That are then declaired as a pointer as follows:

[fortran]

      TYPE(TTYPEAUX), POINTER:: DATA

      ALLOCATE(DATA)

[/fortran] 

After the pointer has been allocated the various allocatable parts in the data type are allocated. 

My question is will there be any memory leaks or problems if at the end of the code or when I no longer need the pointer I just use the following:

[fortran]

      DEALLOCATE(DATA)

[/fortran] 

Which would then DEALLOCATE the data type and all the allocatable arrays within it.

For that matter if DATA was only a regular pointer array would it deallocate the entire array or do I have to do something like:

[fortran]

      DATA=>NULL()

C or

      NULLIFY(DATA)

[/fortran] 

To remove it from memory or would those only disassociate the pointer leaving the array sitting in memory. (There maybe other features pointing to the pointer array.)

I personally hate pointers, but for this particle program that I am working on I have to use them.

 

Thanks for your help as always!

0 Kudos
17 Replies
Andrew_Smith
Valued Contributor I
2,402 Views

If you use a pointer allocation you will always need to explicitly deallocate to clear memory, unless you are terminating the program in which case the OS will clear the memory but it is probably better practice to code a deallocate.

The allocatable components should in theory be cleared automatically without coding.

0 Kudos
ScottBoyce
Beginner
2,402 Views

Thanks Andrew, that is what I suspected, but wanted to make sure.

With the DEALLOCATE statement would also nullify all pointers that point to the original pointer. For example:

[fortran]

INTEGER,POINTER:: A,B

ALLOCATE(A)

B=>A

DEALLOCATE(A)

[/fortran]

would also nullify B?

0 Kudos
Steven_L_Intel1
Employee
2,402 Views

No, it does not. The other pointers now have "undefined" status, which means you can't depend on their value.

0 Kudos
ScottBoyce
Beginner
2,402 Views

That is fine, I just wanted to make sure that B would no longer hold the information or keep the the INTEGER stored in RAM.

0 Kudos
Steven_L_Intel1
Employee
2,402 Views

Once you deallocate A you don't know what B points to. Practically speaking, it will still point to the memory it did before, but that memory could have been reused. There is no way to detect whether or not it is still valid.

0 Kudos
ScottBoyce
Beginner
2,402 Views

Ok cool, so say that B points to A, which is an array that uses 1GB or RAM.

When I deallocate A then the memory would be freed? (i.e. my ram usuage would go down 1GB.) 

or should I also have Nullify(B)

0 Kudos
Steven_L_Intel1
Employee
2,402 Views

The memory is released to the pool that can be allocated, but in nearly all cases, your RAM usage will not decrease.

Yes, an explicit nullify of B would be a good idea in this case.

0 Kudos
ScottBoyce
Beginner
2,402 Views

Either

[fortran]

nullify(B)

C or

B=>NULL()

[/fortran]

Could I so something like?

[fortran]

DEALLOCATE(A)

B=>A

[/fortran]

Thanks so very much for your help with this, I am working on a huge gov modeling software and trying to improve/update it.

0 Kudos
Steven_L_Intel1
Employee
2,402 Views

You could do B=>A, but I strongly recommend against this as it is unclear to the reader what is going on. NULLIFY(B) is the preferred approach.

0 Kudos
ScottBoyce
Beginner
2,402 Views

Sorry about the original incorrect psuedocode. I was trying to simplify about 10000 lines of code and how the pointers were handled between the various subroutines. They use a generic variable "B" and global storage variables "A" and "C" and they flip to have B point to A and C when it is uses.

-----------------------------------------------------------------------------------

OK thanks a ton, that is what I will do. Now that I recheck the code I realized its slightly different in how it allocates. The following is an example

[fortran]

       INTEGER,DIMENSION(:),POINTER:: A,C

       INTEGER,DIMENSION(:),POINTER:: B

      B=>A   !A is undef

       ALLOCATE (B(10000))

C DO SOME STUFF WITH B

       A=>B    !Software considers this saving A

      B=>C    !C is undefined

       ALLOCATE (B(10000))

C DO STUFF WITH B

C THEN 

       C=>B   !Software considers this saving C

C THEN WHEN STUFF FROM A IS NEDED

      B=>A

C DO STUFF WITH B

C THEN WHEN A AND C ARE NO LONGER NEEDED (AND NEITHER IS B)

       DEALLOCATE(A)

       DEALLOCATE(C)

[/fortran]

 

That is a just a psuedocode for it, but it flips back and forth between multiple pointers. At the end of the code I should then also include

[fortran]

NULLIFY(B)

[/fortran]

To be consistent.

 

Thank you so very much for all your help with this, its been really illuminating.

0 Kudos
FortranFan
Honored Contributor II
2,402 Views

Based on your pseudo-code example, I suggest:

  • Applying the TARGET attribute instead for POINTER for B
  • DEALLOCATE B, but use IF (ALLOCATED(B)) a safety check
  • Use IF (ASSOCIATED(..) before using A and C
  • NULLIFY A and C before procedure end (or program termination)
0 Kudos
Andrew_Smith
Valued Contributor I
2,402 Views

Your pseudo code is dodgy since you loose track of the memory you allocate to B. The line B => C points to a unassociated pointer (or rather one with undefined state).  Then you point A at B and you have lost all pointers to the memory.

I don't see why you cannot use a base variable with allocatable and target attributes to hold the data. You can have all the pointers you want to point at it and there is never a danger of memory leaking whatever you do with the pointers.

0 Kudos
ScottBoyce
Beginner
2,402 Views

Hi Andrew, sorry I did make a few mistakes in the psuedocode and fixed it so its not so ambiguous. See the post above.
 

The way to view it is that the pointer variables A and C hold the data and B is a variable used within the subroutines. I think this was introduced into the code as a method of expanding the utility of the original code (A and C are in the code are actually an index of a global data type that represent different features). The psuedocode that I fixed above is the general structure of the code if it was indexed to have two terms (e.g. A and C)

Thanks

0 Kudos
ScottBoyce
Beginner
2,402 Views

Has anyone had a chance to look at that revised code?

0 Kudos
IanH
Honored Contributor II
2,402 Views

The revised code looks ok, but there are pointless statements in it - lines 03 and 07, where you change the pointer association status of B to be undefined, and then immediately re-associate it with an object that you allocate.

In the absence of some other reason that is yet to be stated, I absolutely wouldn't deliberately design things this way.  Andrew's suggestion is reasonable.  There's also the option of simply making B a procedure argument (if it isn't already) in the bits titled "do things with B" - when you want to work on A, pass in A, when you want to work on C, pass in C.  Is there a real reason to have B floating around in the same scope as A and C?

0 Kudos
ScottBoyce
Beginner
2,402 Views

The program is unfortunately enormous and was later modified to be able to run with multiple copies of itself within it by the above pointer scheme.

 

At the beginning of each subroutine there was an added call to a "point" subroutine that establishes all the pointers (B pointing to the active data set, say A) then at the end of each subroutine it saves the pointers by calling a "save" subroutine that re-points A to B. Then the next time the subroutine was called the beginning would have B point to C and then at the end save it by having C point to B. 

 

This was done (long before my time) because there were literally 1000's of variables that change across a few hundred subroutines and made it so only two lines had to be added for each subroutine. Ultimately if there ever is funding I love to rewrite it to not follow this structure.

 

Thanks for all your advice.

0 Kudos
FortranFan
Honored Contributor II
2,402 Views

Scott B. wrote:

The program is unfortunately enormous and was later modified to be able to run with multiple copies of itself within it by the above pointer scheme.

At the beginning of each subroutine there was an added call to a "point" subroutine that establishes all the pointers (B pointing to the active data set, say A) then at the end of each subroutine it saves the pointers by calling a "save" subroutine that re-points A to B. Then the next time the subroutine was called the beginning would have B point to C and then at the end save it by having C point to B.

This was done (long before my time) because there were literally 1000's of variables that change across a few hundred subroutines and made it so only two lines had to be added for each subroutine. Ultimately if there ever is funding I love to rewrite it to not follow this structure.

Scott B.,

To be frank, I've no comprehension whatsover of what you are trying to convey by your pseudo-code or by your explanations.  Statements such as "The program.. was later modified to be able to run with multiple copies of itself within it by the above pointer scheme" and ".. then at the end of each subroutine it saves the pointers by calling a "save" subroutine that re-points A to B.. " are completely beyond my abilities to understand what could be going on.

"I love to rewrite it to not follow this structure" - perhaps it will help you if you can start off by writing a simple, working program that operates on a small set of data in about the same fashion as your existing code and you test and validate it thoroughly - this is as opposed to postulating some pseudo-code that is not constrained by any logic/algorithmic requirements and which is difficult to understand.  This approach may even help you understand better how your current code works while giving you ideas on how to restructure it when you get the funding to do so.

0 Kudos
Reply