- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello! In the code I use, I saw that the data in common statements is maintained when dynamically reassigned. I need advice on whether there is a problem in terms of memory leak.
These are lines 17 and 24 in the code.
After the initial allocation and values of A and B were declared, they were reallocated. If you check in the reallocation subroutine, you see deallocate(ARRAY1) and ARRAY1=>null(). However, if I allocate(ARRAY1(INEX2, IND0)), the previously used value is included. It appears to be the effect of common block.
The overall flow is as follows.
In subroutines that perform dynamic allocation and reallocation, use implicit none.
Otherwise, use it by declaring it like this: IMPLICIT REAL*8 (A-H, O-Z), INTEGER*4 (I-N)
And the types of common statements include A, which consists only of dynamically allocated pointer arrays, and B, which does not.
Both commons have the same problem.
In the subroutine that performs dynamic allocation and reallocation, the pointer points to null after memory is deallocated. Immediately after memory allocation, it is set to 0 or the initial value.
Please give me some general advice on the programs I use.
Because it is a very large program, it may not be possible to fix all the parts advised. For example, it is almost impossible to change it to implicit none.
There may be some insufficiencies due to the abbreviation of the code. The code is as follows.
+++
When I checked while recompiling with a unit test project, I found that the temporarily allocated local variable set ARRAY_TMP also had a value as soon as it was allocated. The values of the array that were examined immediately after allocation were as follows. 1. Initialized groups of 0,0,0, etc. 2. 1, 2, 3, sequential groups 3. Garbage value groups
This is what I came up with after looking at the values of the groups. As soon as it was assigned, it was connected to an address somewhere. Each address can have a value but is not assigned. The fact that the address can be used means that it has been connected in an assignable state. So, it must be initialized to 0 or some other value before use.
In the case of memory leaks, if allocation and deallocation were done normally, there would be no need to worry regardless of null initialization. However, frequent allocation and deallocation can cause memory fragmentation. I should worry about this. I've been looking for strategies for memory fragmentation, but currently the entire program has 10 arrays, and in some cases the size increases through reallocation. If I release and allocate it right away, will A31,,,A50 be added from A1,,,A30? Or will it be the new B1,,,B50? I also wonder if tracking is impossible.
As mentioned before, it is a very large project and there is a lot of code involved, so fixing it is not simple.
!****************************************************************************
program fortran_TEST
IMPLICIT REAL*8 (A-H, O-Z), INTEGER*4 (I-N)
print *, 'Hello World'
call main_alloc()
end program fortran_TEST
subroutine main_alloc()
IMPLICIT REAL*8 (A-H, O-Z), INTEGER*4 (I-N)
Interface
Subroutine real_allocate_2D(ARRAY1, INDEX1, INDEX2, IND0, I_DEC)
Integer*4:: INDEX1, INDEX2, IND0
Integer*4:: I_DEC
Real*8, Pointer:: ARRAY1(:,:)
END Subroutine
END Interface
common /NUM_G_A/ MAX_A
real*8, pointer:: A(:,:)
common /G_CO_A/ A
common /NUM_G_B/ MAX_B
real*8, pointer:: B(:,:)
common /G_CO_B/ XX_PSS(2,30,20), XV_PSS(2,30,20), B
NEW_V = 10
MAX_A = 5
call real_allocate_2D(A, 1, MAX_A, 10, 0) !Initial allocation A(5,10)
call Init_REAL_2D (A, MAX_A, 10)
call real_allocate_2D(A, MAX_A, NEW_V, 10, 1) ! Re-allocate A(5,10) -> A(10,10)
MAX_A = NEW_V
MAX_B = 5
call real_allocate_2D(B, 1, MAX_B, 10, 0) !Initial allocation B(5,10)
call Init_REAL_2D (B, MAX_B, 10)
call real_allocate_2D(B, MAX_B, NEW_V, 10, 1) ! Re-allocate B(5,10) -> B(10,10)
MAX_B = NEW_V
return
end subroutine main_alloc
subroutine Init_REAL_2D(ARRAY1, IND0, IND1)
Implicit none
Integer*4 :: IND0, IND1, i, j
Real*8 :: ARRAY1(IND0,IND1), k
k = 1.0d0
DO j = 1, IND1 !RT_V3(N_RT_V3, 3)
DO i = 1, IND0
ARRAY1(i,j) = k
k = k + 1.0d0
END DO
END DO
RETURN
end subroutine
subroutine COPY_REAL(ARRAY1, ARRAY2, IND0)
IMPLICIT REAL*8 (A-H, O-Z), INTEGER*4 (I-N)
DIMENSION ARRAY1(IND0), ARRAY2(IND0)
ARRAY1 = ARRAY2
RETURN
end subroutine COPY_REAL
subroutine real_allocate_2D(ARRAY1, INDEX1, INDEX2, IND0, I_DEC)
!I_DEC = 0 initial allocation IDEC = 1 reallocation
Implicit none !allocate ARRAY1(INDEX2, IND0)
Integer*4:: INDEX1, INDEX2, IND0, INDEX_MIN
Integer*4 :: I_DEC, i, j
Real*8, Pointer:: ARRAY1(:,:)
Real*8, Pointer:: ARRAY_TMP(:,:) => null()
!
IF (IND0 .LE. 0 .OR. INDEX2 .LE. 0 ) THEN
IF(ASSOCIATED(ARRAY1)) DEALLOCATE(ARRAY1)
ARRAY1 => null()
RETURN
ELSE IF (INDEX1 .LE. 0 .OR. ASSOCIATED(ARRAY1) .EQ. .FALSE.) THEN !INDEX2 .GT.0 .AND. INDEX1 .LE. 0
IF(ASSOCIATED(ARRAY1)) DEALLOCATE(ARRAY1)
ARRAY1 => null()
Allocate(ARRAY1(INDEX2, IND0))
ARRAY1 = 0.0d0
RETURN
ENDIF
!
IF(I_DEC .EQ. 1) THEN
Allocate(ARRAY_TMP(INDEX2,IND0))
ARRAY_TMP = 0.0d0
INDEX_MIN = MIN(INDEX1, INDEX2)
!DO i = 1, IND0
!call COPY_REAL(ARRAY_TMP(1, i), ARRAY1(1, i), INDEX_MIN)
!END DO
!The code ran properly in the original project, but it didn't work here, so this is a double loop that was added.
DO J = 1, IND0
DO i = 1, INDEX_MIN
ARRAY_TMP(i, j) = ARRAY1(i, j)
END DO
END DO
!
If(ASSOCIATED(ARRAY1) .EQ. .TRUE.) DEALLOCATE(ARRAY1)
ARRAY1 => null()
Allocate(ARRAY1(INDEX2,IND0))
call COPY_REAL(ARRAY1, ARRAY_TMP, IND0*INDEX2)
DEALLOCATE(ARRAY_TMP)
ARRAY_TMP => null()
ELSE IF(I_DEC .EQ. 0 .OR. I_DEC .EQ. 2)THEN
If(ASSOCIATED(ARRAY1) .EQ. .TRUE.) DEALLOCATE(ARRAY1)
ARRAY1 => null()
Allocate(ARRAY1(INDEX2,IND0))
ARRAY1 = 0.0d0
ELSE
Write(*,*) 'Vivid] Wrong data, REAL_ALLOC for I_DEC = ', I_DEC
stop
END If
!
RETURN
end subroutine real_allocate_2D
Thank you for taking your valuable time to read my code.
Sincerely yours,
Vivid
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am not sure that COMMON-blocks and pointers/allocatables can be reliably combined, but you can easily avoid that sort of questions by storing the variables that now go into the COMMON-blocks, in modules. That would mean a much more secure way of sharing information - COMMON-blocks merely pass the starting address of a piece of memory and you are yourself responsible for making sure that you use that correctly. Modules allow the compiler to check things thoroughly. (You do lose some flexibility, but mostly the flexibility to play all manner of memory tricks, which are at best tricks.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
hello. Thank you for answer. First of all, it is possible to operate common blocks in flexible sizes through dynamic allocation. I found several documents to try it for the first time and it has been used almost daily in the program for over 3 years now.
Are you of the opinion that by using modules, you can manage code stably with the help of the compiler? Let's make it and test it. Thank you again.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I searched for related articles and checked it in a test project. The dynamic allocation operation was also implemented as a module, and the composition of common statements was also implemented as a module. The problem now is to configure a subproject to convert all 60 megabyte projects into modules.
Before implementing this project, an internal meeting is needed at the company. If you know a link to a highly reliable resource, please recommend it. There is a need to know what the difference is in terms of memory and to provide evidence that it will take a lot of work for now, but it must be done for the future.
Sincerely yours,
Vivid
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Common blocks in a large body of code can be a heap of trouble. They are also marked "obsolescent" in Fortran 2018 and newer:
5.33 New obsolescences
5.33.1 common and equivalence
The common and equivalence statements and the block data program unit are now all obsolescent. Common blocks are error-prone and have largely been superseded by modules. The
equivalence statement is similarly error-prone. Whilst use of these statements was invaluable
prior to Fortran 90, they are now redundant and can inhibit performance. The block data
program unit exists only to initialize data in common blocks and hence is also redundant.
Here is an example of the kind of trouble that converting from common blocks to modules involves, taken from TOMS658:
In one place, we see
common /ode001/ rownd,
1 conit, crate, el(13), elco(13,12), hold, rmax,
2 tesco(3,12), ccmax, el0, h, hmin, hmxi, hu, rc, tn, uround,
3 iownd1(14), ipup, meo, nqnyh, nslp,
4 ialth, lmax, icf, ierpj, iersl, jcur, jstart, kflag, l, meth,
5 miter, maxord, maxcor, msbp, mxncf, n, nq, nst, nfe, nje, nqu
and, in other places, we see several other lists of variables for the same block, one of which is
common /ode001/ rode1(219), iode1(39)
In order to see which variable in one version matches which variable in another version of the same block, you have to compute the byte offset from the base of the block. For example, "ipup" is the same as iode1(15).
On top of this, you may have other variables equivalenced to some of these common block member variables, and Block Data subprograms to initialize these variables. It may take a significant amount of work to convert these common blocks to modules, and another significant amount of work to avoid introducing new bugs. An important intermediate step is to replace these disparate versions of each common block by a single include file, make sure that the program is working correctly after such replacement, and then use a Fortran tool such as SPAG to do the final conversion.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Your program is invalid for the following reason: subprograms that have allocatable or pointer arguments require explicit interfaces in their callers. You have not made such interfaces available. As a result, the program behavior is undefined.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you very much. If you have time, please review the newly written text and code again.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The code supplied will not compile in IFX or IFORT it has several basic errors.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I created a new unit project and checked its compilation and operation. Originally, I attached the code by changing only the variable names in the actual code for the purpose of briefly explaining the situation. Thank you very much for watching that my code actually run it. If you have time, please review the newly written text and code again. Please understand that if you copy and paste the project code, the indentation will be broken, making it difficult to read.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I created a new unit project and checked its compilation and operation. Originally, I attached the code by changing only the variable names in the actual code for the purpose of briefly explaining the situation. Thank you very much for watching that my code actually run it. If you have time, please review again. Please understand that if you copy and paste the project code, the indentation will be broken, making it difficult to read.
When I checked while recompiling with a unit test project, I found that the temporarily allocated local variable set ARRAY_TMP also had a value as soon as it was allocated. The values of the array that were examined immediately after allocation were as follows. 1. Initialized groups of 0,0,0, etc. 2. 1, 2, 3, sequential groups 3. Garbage value groups
This is what I came up with after looking at the values of the groups. As soon as it was assigned, it was connected to an address somewhere. Each address can have a value but is not assigned. The fact that the address can be used means that it has been connected in an assignable state. So, it must be initialized to 0 or some other value before use.
In the case of memory leaks, if allocation and deallocation were done normally, there would be no need to worry regardless of null initialization. However, frequent allocation and deallocation can cause memory fragmentation. I should worry about this. I've been looking for strategies for memory fragmentation, but currently the entire program has 10 arrays, and in some cases the size increases through reallocation. If I release and allocate it right away, will A31,,,A50 be added from A1,,,A30? Or will it be the new B1,,,B50? I also wonder if tracking is impossible.
As mentioned before, it is a very large project and there is a lot of code involved, so fixing it is not simple.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As Dr. Fortran advises in one of his articles, instead of
If(ASSOCIATED(ARRAY1) .EQ. .TRUE.) DEALLOCATE(ARRAY1)
you should be writing
If(ASSOCIATED(ARRAY1)) DEALLOCATE(ARRAY1)
and, instead of
ELSE IF (INDEX1 .LE. 0 .OR. ASSOCIATED(ARRAY1) .EQ. .FALSE.) THEN
you should write
ELSE IF (INDEX1 .LE. 0 .OR. .not.ASSOCIATED(ARRAY1)) THEN
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page