A hole is defined as a chunk of memory not in current use. Holes develop as jobs are loaded, run and then finish. Reclaimed memory from dead jobs often gives rise to many small holes. Operating systems try to merge adjacent holes in order to find the largest chunk of available memory possible for new jobs. By the way, memory itself doesn't look any different between holes and jobs. This is only a fiction in the "mind" of the operating system, which keeps track of which regions of memory belong to its jobs.
When there are many holes and not enough memory in any one place to load a new job that wants to come in, we say that memory is fragmented, as if the chunk of available memory is broken into small, unusable pieces. Some systems perform compaction, which is copying jobs around so that all the active jobs are put at one end of the memory and all the holes coalesce at the other end, making one big hole that is usable.
Jobs request a certain amount of memory when they start, leaving enough room for the heap and run-time stack to grow. Commonly, a job doesn't use all the of the memory it requests and we say that memory suffers internal fragmentation, internal because these unused regions are inside programs. The earlier kind of fragmentation is called external fragmentation because it is outside the jobs.
Fig. 12.8.1 illustrates these two types:
Another kind of fragmentation still occurs, which is when a program's memory request is not an even multiple of the frame size. Memory can only be allocated in frames and all frames must be the same size, due to the number of bits in the dynamic address translation hardware. 4096 bytes is a common page size. If a program requests 17.5 frames, it must get 18, even though the last frame is only half used. Many computer scientists call this a form of internal fragmentation because entire frames belong to jobs, even though the job didn't request the memory so it is logically "outside" the job.