📄 jmemmgr.c
字号:
/*
* jmemmgr.c
*
* Copyright (C) 1991, 1992, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file provides the standard system-independent memory management
* routines. This code is usable across a wide variety of machines; most
* of the system dependencies have been isolated in a separate file.
* The major functions provided here are:
* * bookkeeping to allow all allocated memory to be freed upon exit;
* * policy decisions about how to divide available memory among the
* various large arrays;
* * control logic for swapping virtual arrays between main memory and
* backing storage.
* The separate system-dependent file provides the actual backing-storage
* access code, and it contains the policy decision about how much total
* main memory to use.
* This file is system-dependent in the sense that some of its functions
* are unnecessary in some systems. For example, if there is enough virtual
* memory so that backing storage will never be used, much of the big-array
* control logic could be removed. (Of course, if you have that much memory
* then you shouldn't care about a little bit of unused code...)
*
* These routines are invoked via the methods alloc_small, free_small,
* alloc_medium, free_medium, alloc_small_sarray, free_small_sarray,
* alloc_small_barray, free_small_barray, request_big_sarray,
* request_big_barray, alloc_big_arrays, access_big_sarray, access_big_barray,
* free_big_sarray, free_big_barray, and free_all.
*/
/* This code was changed to eliminate the error messages. Christopher Chang,
Summer, 1993.
*/
#define NO_GETENV
#define AM_MEMORY_MANAGER /* we define big_Xarray_control structs */
#include "jinclude.h"
#include "jmemsys.h" /* import the system-dependent declarations */
#ifndef NO_GETENV
#ifdef INCLUDES_ARE_ANSI
#include <stdlib.h> /* to declare getenv() */
#else
extern char * getenv PP((const char * name));
#endif
#endif
/*
* On many systems it is not necessary to distinguish alloc_small from
* alloc_medium; the main case where they must be distinguished is when
* FAR pointers are distinct from regular pointers. However, you might
* want to keep them separate if you have different system-dependent logic
* for small and large memory requests (i.e., jget_small and jget_large
* do different things).
*/
#ifdef NEED_FAR_POINTERS
#define NEED_ALLOC_MEDIUM /* flags alloc_medium really exists */
#endif
/*
* Many machines require storage alignment: longs must start on 4-byte
* boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc()
* always returns pointers that are multiples of the worst-case alignment
* requirement, and we had better do so too. This means the headers that
* we tack onto allocated structures had better have length a multiple of
* the alignment requirement.
* There isn't any really portable way to determine the worst-case alignment
* requirement. In this code we assume that the alignment requirement is
* multiples of sizeof(align_type). Here we define align_type as double;
* with this definition, the code will run on all machines known to me.
* If your machine has lesser alignment needs, you can save a few bytes
* by making align_type smaller.
*/
typedef double align_type;
/*
* Some important notes:
* The allocation routines provided here must never return NULL.
* They should exit to error_exit if unsuccessful.
*
* It's not a good idea to try to merge the sarray and barray routines,
* even though they are textually almost the same, because samples are
* usually stored as bytes while coefficients are shorts. Thus, in machines
* where byte pointers have a different representation from word pointers,
* the resulting machine code could not be the same.
*/
static external_methods_ptr methods; /* saved for access to error_exit */
#ifdef MEM_STATS /* optional extra stuff for statistics */
/* These macros are the assumed overhead per block for malloc().
* They don't have to be accurate, but the printed statistics will be
* off a little bit if they are not.
*/
#define MALLOC_OVERHEAD (SIZEOF(void *)) /* overhead for jget_small() */
#define MALLOC_FAR_OVERHEAD (SIZEOF(void FAR *)) /* for jget_large() */
static long total_num_small = 0; /* total # of small objects alloced */
static long total_bytes_small = 0; /* total bytes requested */
static long cur_num_small = 0; /* # currently alloced */
static long max_num_small = 0; /* max simultaneously alloced */
#ifdef NEED_ALLOC_MEDIUM
static long total_num_medium = 0; /* total # of medium objects alloced */
static long total_bytes_medium = 0; /* total bytes requested */
static long cur_num_medium = 0; /* # currently alloced */
static long max_num_medium = 0; /* max simultaneously alloced */
#endif
static long total_num_sarray = 0; /* total # of sarray objects alloced */
static long total_bytes_sarray = 0; /* total bytes requested */
static long cur_num_sarray = 0; /* # currently alloced */
static long max_num_sarray = 0; /* max simultaneously alloced */
static long total_num_barray = 0; /* total # of barray objects alloced */
static long total_bytes_barray = 0; /* total bytes requested */
static long cur_num_barray = 0; /* # currently alloced */
static long max_num_barray = 0; /* max simultaneously alloced */
LOCAL void
print_mem_stats (void)
{
/* since this is only a debugging stub, we can cheat a little on the
* trace message mechanism... helpful 'cuz trace_message can't handle longs.
*/
/* fprintf(stderr, "total_num_small = %ld\n", total_num_small);
fprintf(stderr, "total_bytes_small = %ld\n", total_bytes_small);
if (cur_num_small)
fprintf(stderr, "cur_num_small = %ld\n", cur_num_small);
fprintf(stderr, "max_num_small = %ld\n", max_num_small);
#ifdef NEED_ALLOC_MEDIUM
fprintf(stderr, "total_num_medium = %ld\n", total_num_medium);
fprintf(stderr, "total_bytes_medium = %ld\n", total_bytes_medium);
if (cur_num_medium)
fprintf(stderr, "cur_num_medium = %ld\n", cur_num_medium);
fprintf(stderr, "max_num_medium = %ld\n", max_num_medium);
#endif
fprintf(stderr, "total_num_sarray = %ld\n", total_num_sarray);
fprintf(stderr, "total_bytes_sarray = %ld\n", total_bytes_sarray);
if (cur_num_sarray)
fprintf(stderr, "cur_num_sarray = %ld\n", cur_num_sarray);
fprintf(stderr, "max_num_sarray = %ld\n", max_num_sarray);
fprintf(stderr, "total_num_barray = %ld\n", total_num_barray);
fprintf(stderr, "total_bytes_barray = %ld\n", total_bytes_barray);
if (cur_num_barray)
fprintf(stderr, "cur_num_barray = %ld\n", cur_num_barray);
fprintf(stderr, "max_num_barray = %ld\n", max_num_barray); */
}
#endif /* MEM_STATS */
LOCAL void
out_of_memory (int which)
/* Report an out-of-memory error and stop execution */
/* If we compiled MEM_STATS support, report alloc requests before dying */
{
#ifdef MEM_STATS
if (methods->trace_level <= 0) /* don't do it if free_all() will */
print_mem_stats(); /* print optional memory usage statistics */
#endif
send_command(ERR3);
receive_command();
exit();
/* ERREXIT1(methods, "Insufficient memory (case %d)", which); */
}
/*
* Management of "small" objects.
* These are all-in-memory, and are in near-heap space on an 80x86.
*/
typedef union small_struct * small_ptr;
typedef union small_struct {
small_ptr next; /* next in list of allocated objects */
align_type dummy; /* ensures alignment of following storage */
} small_hdr;
static small_ptr small_list; /* head of list */
METHODDEF void *
alloc_small (size_t sizeofobject)
/* Allocate a "small" object */
{
small_ptr result;
sizeofobject += SIZEOF(small_hdr); /* add space for header */
#ifdef MEM_STATS
total_num_small++;
total_bytes_small += sizeofobject + MALLOC_OVERHEAD;
cur_num_small++;
if (cur_num_small > max_num_small) max_num_small = cur_num_small;
#endif
result = (small_ptr) jget_small(sizeofobject);
if (result == NULL)
out_of_memory(1);
result->next = small_list;
small_list = result;
result++; /* advance past header */
return (void *) result;
}
METHODDEF void
free_small (void *ptr)
/* Free a "small" object */
{
small_ptr hdr;
small_ptr * llink;
hdr = (small_ptr) ptr;
hdr--; /* point back to header */
/* Remove item from list -- linear search is fast enough */
llink = &small_list;
while (*llink != hdr) {
llink = &( (*llink)->next );
}
*llink = hdr->next;
jfree_small((void *) hdr);
#ifdef MEM_STATS
cur_num_small--;
#endif
}
/*
* Management of "medium-size" objects.
* These are just like small objects except they are in the FAR heap.
*/
#ifdef NEED_ALLOC_MEDIUM
typedef union medium_struct FAR * medium_ptr;
typedef union medium_struct {
medium_ptr next; /* next in list of allocated objects */
align_type dummy; /* ensures alignment of following storage */
} medium_hdr;
static medium_ptr medium_list; /* head of list */
METHODDEF void FAR *
alloc_medium (size_t sizeofobject)
/* Allocate a "medium-size" object */
{
medium_ptr result;
sizeofobject += SIZEOF(medium_hdr); /* add space for header */
#ifdef MEM_STATS
total_num_medium++;
total_bytes_medium += sizeofobject + MALLOC_FAR_OVERHEAD;
cur_num_medium++;
if (cur_num_medium > max_num_medium) max_num_medium = cur_num_medium;
#endif
result = (medium_ptr) jget_large(sizeofobject);
if (result == NULL)
out_of_memory(2);
result->next = medium_list;
medium_list = result;
result++; /* advance past header */
return (void FAR *) result;
}
METHODDEF void
free_medium (void FAR *ptr)
/* Free a "medium-size" object */
{
medium_ptr hdr;
medium_ptr FAR * llink;
hdr = (medium_ptr) ptr;
hdr--; /* point back to header */
/* Remove item from list -- linear search is fast enough */
llink = &medium_list;
while (*llink != hdr) {
llink = &( (*llink)->next );
}
*llink = hdr->next;
jfree_large((void FAR *) hdr);
#ifdef MEM_STATS
cur_num_medium--;
#endif
}
#endif /* NEED_ALLOC_MEDIUM */
/*
* Management of "small" (all-in-memory) 2-D sample arrays.
* The pointers are in near heap, the samples themselves in FAR heap.
* The header structure is adjacent to the row pointers.
* To minimize allocation overhead and to allow I/O of large contiguous
* blocks, we allocate the sample rows in groups of as many rows as possible
* without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
* Note that the big-array control routines, later in this file, know about
* this chunking of rows ... and also how to get the rowsperchunk value!
*/
typedef struct small_sarray_struct * small_sarray_ptr;
typedef struct small_sarray_struct {
small_sarray_ptr next; /* next in list of allocated sarrays */
long numrows; /* # of rows in this array */
long rowsperchunk; /* max # of rows per allocation chunk */
JSAMPROW dummy; /* ensures alignment of following storage */
} small_sarray_hdr;
static small_sarray_ptr small_sarray_list; /* head of list */
METHODDEF JSAMPARRAY
alloc_small_sarray (long samplesperrow, long numrows)
/* Allocate a "small" (all-in-memory) 2-D sample array */
{
small_sarray_ptr hdr;
JSAMPARRAY result;
JSAMPROW workspace;
long rowsperchunk, currow, i;
#ifdef MEM_STATS
total_num_sarray++;
cur_num_sarray++;
if (cur_num_sarray > max_num_sarray) max_num_sarray = cur_num_sarray;
#endif
/* Calculate max # of rows allowed in one allocation chunk */
rowsperchunk = MAX_ALLOC_CHUNK / (samplesperrow * SIZEOF(JSAMPLE));
/* Get space for header and row pointers; this is always "near" on 80x86 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -