This section provides a brief explanation about 32-bit user process models. Every 32-bit user process has its own address space, whose maximum size is 4 GB. An address space is prepared by the kernel as part of the process initialization tasks as a subset of virtual memory address on the system. A 32-bit address space is composed of up to sixteen 256 MB memory chunks called segments. Each segment has a specific purpose illustrated in several figures in the following sections. A segment is divided into smaller size memory chunks called pages. A page is an atomic unit, with which the virtual memory manager (VMM) in the kernel uses to satisfy many different memory requests.
On AIX, the default page size is 4 KB, unless the large page support[3] is used. If the default page size, 4 KB, is used, a segment contains 256 MB / 4 KB = 256 / 4 × 1024 = 64 K = 65,536 pages.
[3] See 3.6, “Large page support” on page 157 for more detail about the large page support.
In the 32-bit user process model, there are several variations, called large memory model and very large memory model, depending on the required heap size for the process. We also explain these models in the following sections:
Section 3.2.2, “Large memory model” on page 116
Section 3.2.3, “Very large memory model” on page 117
Figure 3-3 on page 111 illustrates the segment usage of the default 32-bit memory model. This is the default memory model, unless you explicitly set a linker option (-b:maxdata) when generating executables or set an environment value (LDR_CNTRL) when executing 32-bit executables.
[4] The access to the 0xE segment from a user process has been supported on AIX Version 4.2.1 and later.
The usage of each segment is briefly described in the following:
The first segment, 0x0, is reserved by system for the kernel text and data. Therefore, access from the user process to the segment 0x0 is prohibited.[5]
[5] User processes can access to kernel data only through the system calls with specific ways.
The 0x1 segment contains user process text. If another process shares the same executable file, there will be only one instance of the text pages for that executable file on the system.
The 0x2 segment contains user data, heap, and stack. We provide detailed information about this segment in “Process private segment (0x2)” on page 111.
The 0xD segment contains shared library text. This segment is shared by all 32-bit user processes. The virtual addresses of loaded shared text objects can be examined using the genkld command. For further information about the usage of genkld, see 2.7.2, “genkld” on page 88.
The 0xF segment contains per-process shared library data.
Segments 0x3 - 0xC and 0xE are attached to the address space if the process called shmat() or mmap() routines to allocate shared memory segments. These segments are allocated in order, starting from 0x3 towards 0xE excluding 0xD, unless DSA (Dynamic Segment Allocation) is used. Further detailed explanation is provided in 3.5.1, “Order in the 32-bit default memory model” on page 153 and 3.5.2, “Order in the 32-bit very large memory model with DSA” on page 154.
The process private segment, 0x2, is the most interesting segment for application developers on AIX. In this segment, many memory components that are mandatory for a user process are allocated (see Figure 3-3). In this figure, white rectangles represent un-allocated virtual address pages; if a process touches these address ranges, it receives the SIGSEGV[6] signal and dumps a core file. Highlighted rectangles represent allocated virtual address pages. You may notice that a 32-bit address space is quite vacant in most cases.
[6] Signal for segmentation violation
First of all, some pages within this segment are prepared by the kernel as a part of the process initialization tasks. The access to those pages from the user process is prohibited (represented as several highlighted rectangles under the Kernel in the right most rectangle). The information contained in this area are only accessible from the user process through system calls.
The rest of the pages within this segment can be accessed by the process, though there is a big hole between the process heap (represented as “User data” in the figure) and stack. If the process touches pages in this hole, it receives the SIGSEGV signal and dumps a core file.
User data contains three different memory components: initialized data, un-initialized data,[7] and heap. To demonstrate how they are mapped into virtual pages, we have prepared a simple program shown in Example 3-2 on page 113.
[7] The un-initialized data is generally referred to as BSS (block started by symbol) in computer science terminology.
When compiled and executed, it prints addresses of several predefined symbols in the XCOFF format, as shown in Example 3-1. Those symbols, starting from the underscore character, are well explained in “XCOFF Object (a.out) File Format”, AIX 5L Version 5.2 Files Reference. We only explain _data and _edata here; the _data symbol defines the starting address of the initialized data in the executable file, while the _edata symbol defines the first location address after the initialized data in the executable file.
The size command tells you the size of the .text, .data, and .bss segments of the specified executable file.[8]
[8] The -x option instructs the command to display data in the hexadecimal format.
$ size -fx a.out a.out: 428(.text) + 234(.data) + 8(.bss) + 2db(.loader) = 0x93f $ a.out _text = 0x10000128 _etext = 0x10000550 _data = 0x20000550 _edata = 0x20000784 argv[] = 0x2ff22a14 environ[] = 0x2ff22ff4 errnop = 0x2ff22ffc errno = 0x2ff22ff8 i_initialized = 0x200006f0 l_uninitialized = 0x20000788 str_buf = 0x2ff219b0 heap_mem = 0x20000798 |
As for the addresses of_data and_edata, we can easily subtract 0x20000550 from 0x20000784 using the bc command, as shown in the following example:
$ bc
ibase=F
obase=F
20000784 - 20000550
234
^D
To quit the command, type Control-D. The ibase=F and obase=F keywords instruct the command to treat both input and output as hexadecimal numbers. The answer is 0x234, which is equivalent to the .data segment size in the executable file reported by the size command.
Note
You need to use upper-case characters (A - F) to represent hexadecimal 0xA - 0xF with the bc command.
After the initialized data, un-initialized data (BSS) is loaded into the memory as shown by the address of l_uninitilized. Then heap starts as shown by the address of heap_mem. It grows toward the last address of this segment (0x2FFFFFFF).
On the other hand, the stack grows from a relatively higher address toward the first address of this segment (0x20000000). The user process stack contains several predefined symbols, such as argv, environ, errno, and so on. The user process stack grows, if the process calls functions or allocates auto storage class symbols.
Note
Thread stacks for Pthreads, except the initial thread within a multi-threaded processes, are allocated in the process heap. See 8.3.4, “Thread stack” on page 292 for further information about the thread stack for multi-threaded processes.
#include <stdlib.h> #include <stdio.h> #include <errno.h> extern int errnop; extern int errno; extern _text; extern _etext; extern _data; extern _edata; extern char *environ[]; int i_initialized = 1; /* initialized global variable. */ long l_uninitialized; /* uninitialized global variable. */ int main(int argc, char *argv[]) { char str_buf[BUFSIZ]; /* auto storage class variable. */ char *heap_mem; /* heap memory. */ if ((heap_mem = malloc(BUFSIZ)) == (void *)NULL) { sprintf(str_buf, "malloc() failed with errno = %d", errno); perror(str_buf); } printf("_text = 0x%08p ", &_text); printf("_etext = 0x%08p ", &_etext); printf("_data = 0x%08p ", &_data); printf("_edata = 0x%08p ", &_edata); printf("argv[] = 0x%08p ", argv); printf("environ[] = 0x%08p ", environ); printf("errnop = 0x%08p ", &errnop); printf("errno = 0x%08p ", &errno); printf("i_initialized = 0x%08p ", &i_initialized); printf("l_uninitialized = 0x%08p ", &l_uninitialized); printf("str_buf = 0x%08p ", str_buf); printf("heap_mem = 0x%08p ", heap_mem); exit(0); } |
[9] Extern symbols start with underscore are run-time symbols prepared by the system loader.
Because the process heap and stack share the same segment, the heap size must be smaller than 256 MB in the default memory model. This is the reason why the default definition of user soft data limit is 131,072 KB = 128 MB (see Example 3-6 on page 125).
We provide detailed information about how heap and stack grows in this segment in 3.2.6, “Resource limits in 32-bit model” on page 125.
Environment variables are accessible from a process using either of the following, regardless of user process models, including 64-bit:
The environ extern symbol (see Example 3-2 on page 113).
The third parameter of the main() routine. This parameter is commonly represented as envp, as shown in the following example:
int main(int argc, char *argv[], char *envp[]);
The getenv() sub-routine call.
On AIX, environment variables are copied into the process stack by the system loader as a part of the process initialization tasks. The maximum size of environment variables per process are defined by a system-wide configuration value, ncargs, as shown in the following example:[10]
[10] The ncargs system parameter has been supported on AIX since Version 5L Version 5.1.
# lsattr -El sys0 -a ncargs ncargs 6 ARG/ENV list size in 4K byte blocks True
The default value 6 means 6 pages x 4 [KB/page] = 24 KB. If a process is given environment variables that require more than ncargs x 4 KB, those environment values that exceeded the value will not be copied into virtual pages and cannot be accessed by the process.
If you need to increase ncargs, do either of the following as the root user:
Use the chattr command:
# chattr -El sys0 -a ncargs=N
where N is the number of pages that can be used for environment variables per-process basis.
Use SMIT
Select System Environments → Change / Show Characteristics of Operating System, then specify an appropriate number in the “ARG/ENV list size in 4K byte block” field, and then press Enter.
In both ways, the minimum value is 6, and the maximum value is 128 (512 KB). This change takes affect immediately and is preserved over boot.
Note
The default value ncargs = 6 is sufficient for most processes. Change it only when your applications absolutely require a larger size of environment variables. If there are many processes that require a large size of environment variables, those processes may consume a significant amount of memory.
Although many 32-bit applications do not require a heap size more than 256 MB, there has been a huge demand to run 32-bit user processes with a larger size of initialized data, process heap, or process stack. To address this demand, AIX has been supporting another memory model called large memory model, as a variation of the 32-bit user process model.
The concept of the large memory model is simple. By sacrificing segments available for shared memory segments, the user process running in the large memory model can place its heap on those segments (see Figure 3-4).
In Figure 3-4, four segments (0x3 - 0x6) are reserved for heap, so seven segments (0x7 - 0xC and 0xE) are available for shared memory segments.
Because the process heap and initialized and un-initialized data are moved from the 0x2 segment to 0x3, the user stack can enjoy more room in the 0x2 segment in this model.
To apply the large memory model to your application programs, see 3.2.4, “Using the large and very large memory model” on page 121.
Note
In the large memory model, the soft data limit of a process has a slightly different effect (see 3.2.6, “Resource limits in 32-bit model” on page 125).
In addition to the large memory model, AIX 5L Version 5.2 supports another model, called very large memory model, as a variation of the 32-bit user process model. AIX 5L Version 5.1 also supports some of the features provided by the very large memory model; it does support up to 2 GB heap memory, but not up to 3.25 GB.
Although the concept of the very large memory model remains the same, there are three different allocation mechanisms, depending on the maxdata value setting explained in 3.2.6, “Resource limits in 32-bit model” on page 125:
“Heap size less than 2.5 GB” on page 117
“Heap size greater than 2.5 GB” on page 118
“Heap size less than 256 MB” on page 119
To apply the very large memory model to your application programs, see 3.2.4, “Using the large and very large memory model” on page 121.
Note
In the very large memory model, the soft data limit of a process has a slightly different effect (see 3.2.6, “Resource limits in 32-bit model” on page 125).
The big difference between the very large memory model and the large memory model is that segments can be dynamically allocated. In the large memory model, the allocation of segments are rigid, and there is no way to alter this segment allocation while executing the application program. The very large memory model relaxes this limitation by providing a new function, called dynamic segment allocation (DSA).
With DSA, segments are dynamically allocated to either the process heap or shared memory segments in the address space. Once a segment is allocated to either the process heap or shared memory segments, it cannot be returned to the free pool of segments, even if all virtual pages in the segment are relinquished.
In Figure 3-5 on page 118, we are assuming that a process is running with maxdata=0xA0000000 and the DSA option specified, which means the process can acquire heap memory up to 10 segments (2.5 GB).
Another big difference between the very large and large memory models is the direction of how shared memory segments are allocated. In this figure, shared memory segments will be allocated in the segments, starting from 0xE, 0xC, 0xB, and on towards 0x3, if the target segments are not already allocated to the process heap. To understand how these segments are allocated, see 3.5.2, “Order in the 32-bit very large memory model with DSA” on page 154.
Because of the process heap, initialized and un-initialized data are moved from the 0x2 segment to 0x3, and the user stack can enjoy more room in the 0x2 segment in this model.
Note
AIX 5L Version 5.1 supports this model only when maxdata is less than or equal to 0x80000000.
If a process is running with maxdata=0xB0000000 and greater with DSA, then the address space has a significant change; there are no shared text segments available, as shown in Figure 3-6 on page 119. Therefore, all the shared text and data that are referenced by the process will be loaded into the 0x2 segment, as private shared objects, even if the other processes has already loaded shared objects into the system memory. The process performance might be affected by this change.
However, by sacrificing segments 0xD - 0xF, the process can acquire heap memory up to 13 segments (3.25 GB). Also, shared memory segments will be allocated in the segments, starting from 0xF, 0xE, 0xD, and on towards 0x3, if the target segments are not already allocated to the process heap. To understand how these segments are allocated, see 3.5.2, “Order in the 32-bit very large memory model with DSA” on page 154.
If a process is running with maxdata=0 with DSA, then all the following memory components are packed into the 0x2 segment:
Initialized data
Uninitialized data
Process heap
Process stack
Shared library text
Shared library data
Apparently, this does not provide much room for the process heap; in fact, it is smaller than the default memory model. However, it ensures that all 13 segments (3.25 GB) are available for shared memory segments in the address space. Some application programs that manage their own memory requests on shared memory segments can exploit this memory model. To understand how these segments are allocated, see 3.5.2, “Order in the 32-bit very large memory model with DSA” on page 154.
Note
If you decide to apply this memory model to your application, it is your responsibility to ensure that the process heap and stack usage are well managed. You must be aware that the 0x2 segment can be easily corrupted in this model.
Note
On AIX 5L Version 5.1, shared library text and data will be loaded into segments 0xD and 0xF in this model (maxdata=0 with DSA).
This model does not support large pages (see 3.6, “Large page support” on page 157).
To use the large memory model, any one of the following methods are supported:
Specify the -bmaxdata:0xN0000000 linker option when linking your source codes (where N is hexadecimal from 0 to 8).
After compiling the source code, binary-edit the XCOFF header file of the generated executable file using the /usr/ccs/bin/ldedit command. For example:
$ /usr/ccs/bin/ldedit -bmaxdata:0x60000000 a.out
Specify the LDR_CNTRL environment value when running the executable. For example:
$ LDR_CNTRL=MAXDATA=0x80000000 a.out
To use the very large memory model, the following methods are supported:
Specify the -bmaxdata:0xN00000000/dsa compiler option when compiling your source codes (where N is hexadecimal from 0 to D).
After compiling the source code, binary-edit the XCOFF header file of the generated executable file using the /usr/ccs/bin/ldedit command. For example:
$ /usr/ccs/bin/ldedit -bmaxdata:0x80000000/dsa a.out
Specify the LDR_CNTRL environment value when running the executable. For example:
$ LDR_CNTRL=MAXDATA=0xC0000000@DSA a.out
Note
When using the LDR_CNTRL environment variable, the keyword DSA must be upper case character, while dsa must be lower case characters in the other two methods.
To demonstrate the usage, we have prepared the short example program shown in Example 3-3. When executed, it takes an integer as a command line parameter, which will be used as an index to allocate memory with a size of multiplies of 256 MB from the process heap.
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #define ONE_SEG (256 * 1024 * 1024) int main(int argc, char *argv[]) { char *p; char buf[BUFSIZ]; int rc; size_t sz, sz_7; if (argc != 2) { fprintf(stderr, "Usage: %s digit-number ", argv[0]); exit(1); } sz = atoi(argv[1]); if (sz > 7) { sz_7 = sz - 7; if ((p = malloc(7 * ONE_SEG)) == (void *)NULL) { sprintf(buf, "1st malloc() with 7 × 256 MB failed with errno = %d" , errno); perror(buf); } else { printf("1: starting address of 7 × 256 MB memory heap is 0x%08p " , p); printf("1: ending address of 7 × 256 MB memory heap is 0x%08p " , p + (7 * ONE_SEG)); } if ((p = malloc(sz_7 * ONE_SEG)) == (void *)NULL) { sprintf(buf, "2nd malloc() with %d x 256 MB failed with errno = %d" , sz_7, errno); perror(buf); } else { printf("2: starting address of %d x 256 MB memory heap is 0x%08p " , sz_7, p); printf("2: ending address of %d x 256 MB memory heap is 0x%08p " , sz_7, p + (sz_7 * ONE_SEG) - 1); } } else { if ((p = malloc(sz * ONE_SEG)) == (void *)NULL) { sprintf(buf, "malloc() with %d x 256 MB failed with errno = %d" , sz, errno); perror(buf); } else { printf("starting address of %d x 256 MB memory heap is 0x%08p " , sz, p); printf("ending address of %d x 256 MB memory heap is 0x%08p " , sz, p + (sz * ONE_SEG) - 1); } } exit(0); } |
The following example shows the output when we run Example 3-3 on page 121 using the very large memory model on AIX 5L Version 5.1:
$ oslevel -r 5100-03 $ cc grabheap_32.c $ LDR_CNTRL=MAXDATA=0xD0000000@DSA ./a.out 7 starting address of 7 × 256 MB memory heap is 0x30000968 ending address of 7 × 256 MB memory heap is 0xa0000967 $ LDR_CNTRL=MAXDATA=0xD0000000@DSA ./a.out 8 1: starting address of 7 × 256 MB memory heap is 0x30000968 1: ending address of 7 × 256 MB memory heap is 0xa0000967 2nd malloc() with 1 × 256 MB failed with errno = 12: Not enough space
The second call of malloc() failed with errno = 12 (ENOMEM), because it requested another 256 MB in addition to the already acquired 7 × 256 MB (1.75 GB) heap memory. Although AIX 5L Version 5.1 supports the heap size up to 2 GB, there is always a very small amount of overhead memory (initialized and un-initialized data) required in the beginning of segment 0x3 in the large and very large memory model regardless of operating system versions.
The following example shows the output when we run Example 3-3 on page 121 using the very large memory model on AIX 5L Version 5.2:
$ oslevel 5.2.0.0 $ cc grabheap_32.c $ LDR_CNTRL=MAXDATA=0xD0000000@DSA ./a.out 12 1: starting address of 7 × 256 MB memory heap is 0x30000988 1: ending address of 7 × 256 MB memory heap is 0xa0000987 2: starting address of 5 × 256 MB memory heap is 0a0000998 2: ending address of 5 × 256 MB memory heap is 0xf0000997
The first call of malloc() acquired memory from the segment 0x3 to 0xA and the second call acquired memory from the segment 0xA to 0xF; the outcome is clear. This process successfully acquired 12 × 256 MB = 3 GB memory in total. In fact, the program could have requested more memory, roughly 256 MB; therefore, it could have acquired roughly 3.25 GB memory in total.
If your application needs a heap size larger than 2 GB in the very large memory model, then it must call system heap allocation routines, such as malloc() and calloc(), more than once, like we did in Example 3-3 on page 121. The reason for this limitation is that the sbrk() system call, which is internally called from system heap allocation routines, takes a signed integer value as a parameter. Therefore, it cannot extend the break value more than 2 GB within a single call.
For further information about the use of the system heap, see Chapter 4, “Managing the memory heap” on page 165.
After compiling your source code with the -bmaxdata:0xN0000000 option, use the file command with the modified /etc/magic file to check if the o_maxdata field in the XCOFF header of executable is correctly set. On AIX, instead of the /etc/magic file, the file command consults with a locale message file (depending on the current locale setting) by default. Therefore, to have the command refer to the modified /etc/magic file, do the following:
1. | Log in to the system as the root user. |
2. | Create a backup of the original /etc/magic: # cp -p /etc/magic /etc/magic.orig |
3. | Edit the file and add highlighted lines in Example 3-4 using a text editor, then save the file and exit. |
4. | Run the file command against the executable file with the -m /etc/magic option. |
0 short 0x01df executable (RISC System/6000) or object module >12 long >0 not stripped >18 byte 0x14 LP_TEXT >18 byte 0x18 LP_DATA >19 byte >0x3F /DSA >76 long 0x00000000 (maxdata=0) >76 long 0x10000000 (maxdata=1) >76 long 0x20000000 (maxdata=2) >76 long 0x30000000 (maxdata=3) >76 long 0x40000000 (maxdata=4) >76 long 0x50000000 (maxdata=5) >76 long 0x60000000 (maxdata=6) >76 long 0x70000000 (maxdata=7) >76 long 0x80000000 (maxdata=8) >76 long 0x90000000 (maxdata=9) >76 long 0xA0000000 (maxdata=A) >76 long 0xB0000000 (maxdata=B) >76 long 0xC0000000 (maxdata=C) >76 long 0xD0000000 (maxdata=D) 0 short 0x01f7 64-bit XCOFF executable or object module >18 byte 0x14 LP_TEXT >18 byte 0x18 LP_DATA >19 byte >0x3F /DSA >20 long >0 not stripped |
Example 3-5 shows the sample output from the executable file compiled with the -bmaxdata:0x80000000/dsa option.
$ cc -bmaxdata:0x80000000 helloworld.c
$ file a.out
a.out: executable (RISC System/6000) or object module not stripped
$ file -m /etc/magic a.out
a.out: executable (RISC System/6000) or object module not stripped /DSA (maxdata=8)
|
For further information about the /etc/magic file and XCOFF format, please refer to the AIX 5L Version 5.2 Files Reference.
The resource limits are used to regulate several resources consumed by a process on UNIX operating systems. Although the resource limits are set on a per-user basis, they are applied on a per-process basis. Therefore, if a user is executing hundreds of processes, the user may consume huge amounts of resources, even if the resource setting values for the user are relatively small numbers.
To display the current user’s resource limits, use the ulimit command (see Example 3-6).
$ ulimit -Ha time(seconds) unlimited file(blocks) 2097151 data(kbytes) unlimited stack(kbytes) unlimited memory(kbytes) unlimited coredump(blocks) unlimited nofiles(descriptors) unlimited $ ulimit -Sa time(seconds) unlimited file(blocks) 2097151 data(kbytes) 131072 stack(kbytes) 32768 memory(kbytes) 32768 coredump(blocks) 2097151 nofiles(descriptors) 2000 |
The -H option instructs the command to display hard resource limits, while the -S option instructs the command to display soft resource limits. [11] The hard resource limit values are set by the root user using the chuser command for each user. The soft resource limit values can be relaxed by the relaxed by the individual user using the ulimit command, as long as the values are smaller than or equal to the hard resource limit values.
[11] Resource limits are defined in the /etc/security/limits file on a per-user basis.
Although there are seven types of resource limits displayed in Example 3-6 on page 125, we only discuss the data and stack resource limits, which regulate process heap and stack usage. For further information about resource limits, please refer to the command reference of ulimit, found in the AIX 5L Version 5.2 Reference Documentation: Commands Reference.
In the default memory model, soft data and stack resource limits are strictly enforced. During the process initialization tasks, the kernel sets soft data and stack resource limits in the process address space (see Figure 3-8 on page 126). While the process is running, the heap and stack can grow up to the soft data limits from opposite directions, as represented by arrows in the figure.
If either the data or stack soft limit is set to unlimited before the program execution, or if the setrlimit() routine is called to set these limit values to unlimited while the process is running, it is your responsibility to prevent the process stack from being overwritten by the over-grown process heap.
When you execute a program that uses the large memory model, the operating system attempts to modify the soft limit on the data size to match the maxdata value. If the maxdata value is greater than the current hard limit on the data size, either the program will not execute, if the environment variable XPB_SUS_ENV has the value set to ON, or the soft limit will be set to the current hard limit. If the maxdata value is smaller than the size of the program’s static data, the program will not execute.
To demonstrate this behavior, we have prepared a simple program, shown in Example 3-10 on page 128. When compiled and executed, it prints the soft and hard resource limit values by calling the getrlimit() sub-routine.
When we have executed this program in the default memory model, it prints the values shown in Example 3-7 on page 127.
$ a.out Resource name Soft Hard RLIMIT_CORE 1073741312 2147483647 RLIMIT_CPU 2147483647 2147483647 RLIMIT_DATA 134217728 2147483647 RLIMIT_FSIZE 1073741312 1073741312 RLIMIT_NOFILE 2000 2147483647 RLIMIT_STACK 33554432 2147483647 RLIMIT_RSS 33554432 2147483647 |
You will find that this output resembles Example 3-6 on page 125.
On AIX, all hard resource limit values are set to unlimited by default, except for the file resource limit. The value unlimited is defined as 0x7FFFFFFF in the /usr/include/sys/resource.h include file when the program is running in the 32-bit user process model (see Example 3-8).
#if defined(__64BIT__) && !defined(__64BIT_KERNEL) #define RLIM_INFINITY 0x7fffffffffffffffL #else #define RLIM_INFINITY 0x7FFFFFFF #endif /* __64BIT__ */ |
When we have executed this program in the large memory model, it prints the values shown in Example 3-10 on page 128. As shown in this example, the soft data limit value is set to RLIM_INFINITY without using either the ulimit command or the setrlimit() sub-routine.
$ LDR_CNTRL=MAXDATA=0x80000000 a.out
Resource name Soft Hard
RLIMIT_CORE 1073741312 2147483647
RLIMIT_CPU 2147483647 2147483647
RLIMIT_DATA 2147483645 2147483647
RLIMIT_FSIZE 1073741312 1073741312
RLIMIT_NOFILE 2000 2147483647
RLIMIT_STACK 33554432 2147483647
RLIMIT_RSS 33554432 2147483647
|
In fact, when we executed the program shown in Example 3-3 on page 121 using the large and very large memory models, we did not increase the soft data limit value.
Example 3-10 is a program that calls the getrlimit() routine to print current soft and hard resource limit values.
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <sys/time.h> #include <sys/resource.h> #define pr_limit(XXX) print_limit(#XXX, XXX) void print_limit(const char *name, int resource) { int rc; char buf[BUFSIZ]; struct rlimit rlimit; if ((rc = getrlimit(resource, &rlimit)) < 0) { sprintf(buf, "getrlimit() failed with errno = %d, at %d in %s" , errno, __LINE__,__FILE__); perror(buf); } else { printf("%-14s %20ld %20ld " , name, rlimit.rlim_cur, rlimit.rlim_max); } } int main(int argc, char *argv[]) { printf("%-14s %20s %20s ", "Resource name", "Soft", "Hard"); pr_limit(RLIMIT_CORE); pr_limit(RLIMIT_CPU); pr_limit(RLIMIT_DATA); pr_limit(RLIMIT_FSIZE); pr_limit(RLIMIT_NOFILE); pr_limit(RLIMIT_STACK); pr_limit(RLIMIT_RSS); } |
In the computer industry, the term large file is generally considered to refer to a file larger than 2 GB. In the 32-bit user process model, the data type off_t is defined as signed long type. Therefore, by default, 32-bit processes can handle files up to 2 GB -1 byte, which is addressable by the off_t type. If a 32-bit process attempts to seek a file pointer more than 2 GB, then the system call fails with errno EOVERFLOW. This limitation exists on all UNIX operating systems that conform to the POSIX standards.
Beginning with AIX Version 4.2.1, there are two methods to work around the addressability of large files in the 32-bit user process model:
If the -D_LARGE_FILE option is specified when compiling the program, the off_t type is redefined as long long (64-bit signed integer). Also, most system calls and library routines are redefined to support large files.
In some circumstances, your existing 32-bit user programs might be corrupted by defining the _LARGE_FILE macro, especially if off_t is interchangeably used with the int or long type within your source codes. In this case, you can modify your source codes to explicitly call 64-bit versions of file I/O related system calls and library routines, such as fopen64(), lseek64(), and so on. Also, variables defined as the off_t type must be carefully converted to off64_t.
Using one of the above methods, 32-bit processes can handle large files as long as the following conditions are met:
The file hard and soft limits have been relaxed. The default value of file limit is 2,097,151 disk blocks = 1 GB (see Example 3-6 on page 125).
JFS2 or large file enabled JFS is used.
For further information about large file support of the 32-bit user process, please refer to the “Writing Programs That Access Large Files” section in AIX 5L Version 5.2 General Programming Concepts: Writing and Debugging Programs.