- 浏览: 208501 次
- 性别:
- 来自: 重庆
-
文章分类
最新评论
许多书籍提到过内存碎片,也看到一些方法防治内存碎片。一直以来都以为频繁的分配释放内存会导致系统内存碎片过多(虽然这个想法并没有错到离谱)。后来看 过计算机程序设计艺术上面关于伙伴系统的介绍,一般操作系统都采用此种方法来管理内存。频繁分配释放内存确实会导致一些系统负担,但分配的内存释放及时, 内存管理系统将能够急时合并相邻空闲内存块,得到更大的空闲内存。这样并不会导致内存碎片的出现。即使相邻空间不空闲,这样产生的碎片还是比较少的
今天突然醒悟内存碎片的出现主要跟分配有关,特别是分配小而且生命周期很长的内存块时,才容易导致内存碎片的出现。对于伙伴系统,假设有16byte空
间,依次分配一个1,3,5byte空间,在分配4byte,对于伙伴系统将分配不出最后的4byte,尽管还有7byte的额外空间,但这些空间只剩下
1、2byte的空间块,如下图,即使这些伙伴空间都是空闲的,也难以被充分利用。而3、5byte分配后剩下的空间更是由于少于上层空间的一半而被浪费
掉了,不能再进行分配。如果分配的小块内存相当多,将会浪费很多内存空间,导致内存碎片化。当然真正操作系统是32位对齐的,但情行是类似的
所以如果要动态分配的空间比较小,一般采取先分配一大块空间。然后在有内存分配需求时,从大块空间依次取出。如vc中的map list array
等便是如此设计。每个类都先使用CPlex
分配一定数量的CAssoc空间,当空间用完后,在分配相同大小的空间。当然这些空间是链接在一起的。下面是从quake3中摘出来的一部分代码,对于
quake配置参数是一直存在于整个软件运行期的,这些参数依次保存在smallzone空间中。
如果分配的空间很快就会释放(如分配释放同时在一个函数内),那么就不需要考虑内存碎片问题。但是鉴于伙伴系统效率,如果存在大量频繁的分配释放,可以考
虑使用桶状内存管理。即分配一块大的内存zone(当然还需要3个指针,标志zone头尾和当前写入的位置)。而后需要相对小的空间时,直接向zone中
写入,如到zone尾部时,转到zone开头写入。当然以前写的东西就被覆盖了,一定要保证覆盖时这段内存中的东西已经不再需要了。如果想更省事可以考虑
boost pool 内存池,不过 pool 每次分配的块大小总是固定的
void func()
{
boost::pool<> p(256*sizeof(BYTE)); //指定每次分配的块的大小
for (int i = 0; i < 10000; ++i)
{
BYTE* const p = p.malloc(); //pool分配指定大小的内存块;需要的时候,pool会向系统申请大块内存。
... // Do something with t;
p.free( p); //释放内存块,交还给pool,不是返回给系统。
}
//pool的析构函数会释放所有从系统申请到的内存。
}
//注意必须是.c文件。
#define ZONEID 0x1d4a11
typedef enum
{
TAG_FREE,
TAG_GENERAL,
TAG_BOTLIB,
TAG_RENDERER,
TAG_SMALL,
TAG_STATIC
} memtag_t;
typedef struct memblock_s
{
int size; // including the header and possibly tiny fragments
int tag; // a tag of 0 is a free block
struct memblock_s *next, *prev;
int id; // should be ZONEID
} memblock_t;
memzone_t *mainzone;
memzone_t *smallzone;
//只调用一次分配足够内存空间
void Com_InitSmallZoneMemory( void ) {
s_smallZoneTotal = 512 * 1024;
smallzone = calloc( s_smallZoneTotal, 1 );
if ( !smallzone )
{
Com_Error( ERR_FATAL, "Small zone data failed to allocate %1.1f megs", (float)s_smallZoneTotal /(1024*1024) );
}
Z_ClearZone( smallzone, s_smallZoneTotal );
return;
}
//从大的内存空间中逐步取出足够的小块空间
void *S_Malloc( int size)
{
int extra, allocSize;
memblock_t *start, *rover, *new, *base;
memzone_t *zone;
tag =TAG_SMALL;
zone = smallzone;
allocSize = size;
size += sizeof(memblock_t); // account for size of block header
size += 4; // space for memory trash tester
size = (size + 3) & ~3; // align to 32 bit boundary
base = rover = zone->rover;
start = base->prev;
do
{
if (rover == start)
{
Com_Error( ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes from
the %s zone", size, zone == smallzone ? "small" : "main");
return NULL;
}
if (rover->tag)
{
base = rover = rover->next;
} else
{
rover = rover->next;
}
} while (base->tag || base->size < size);
extra = base->size - size;
if (extra > MINFRAGMENT) {
// there will be a free fragment after the allocated block
new = (memblock_t *) ((byte *)base + size );
new->size = extra;
new->tag = 0; // free block
new->prev = base;
new->id = ZONEID;
new->next = base->next;
new->next->prev = new;
base->next = new;
base->size = size;
}
base->tag = tag; // no longer a free block
zone->rover = base->next; // next allocation will start looking here
zone->used += base->size; //
base->id = ZONEID;
*(int *)((byte *)base + base->size - 4) = ZONEID;
return (void *) ((byte *)base + sizeof(memblock_t));
}
void Z_ClearZone( memzone_t *zone, int size ) {
memblock_t *block;
// set the entire zone to one free block
zone->blocklist.next = zone->blocklist.prev = block =
(memblock_t *)( (byte *)zone + sizeof(memzone_t) );
zone->blocklist.tag = 1; // in use block
zone->blocklist.id = 0;
zone->blocklist.size = 0;
zone->rover = block;
zone->size = size;
zone->used = 0;
block->prev = block->next = &zone->blocklist;
block->tag = 0; // free block
block->id = ZONEID;
block->size = size - sizeof(memzone_t);
}
//向内存块中添加字符串
char *CopyString( const char *in )
{
char *out;
if (!in[0]) {
return ((char *)&emptystring) + sizeof(memblock_t);
}
else if (!in[1])
{
if (in[0] >= '0' && in[0] <= '9')
{
return ((char *)&numberstring[in[0]-'0']) + sizeof(memblock_t);
}
}
out = S_Malloc (strlen(in)+1);
strcpy (out, in);
return out;
}
发表评论
-
线程属性pthread_attr_t简介
2013-01-05 10:57 3930本文编辑整理自: http://hi.baidu.c ... -
Linux程序设计中由线程使用不当引起的内存泄漏
2012-12-13 10:27 1402Linux程序设计中,创建线程时调用pthread_ ... -
EPOLL ET 模式下事件触发的场景
2012-09-25 10:13 1880ET模式称为边缘触发模式,顾名思义,不到边缘情况,是死都 ... -
惊群问题的思考
2012-09-25 10:13 942“据说”惊群问题已经是一个很古老的问题了,并且在大多数系统中已 ... -
linux惊群问题之udp
2012-09-25 10:12 1608今天测试udp服务器进程时发现log中记录了 ... -
getaddrinfo()函数详解
2012-09-19 10:59 8801. 概述IPv4中使用gethostbyname()函数完成 ... -
Linux的mmap文件内存映射机制
2012-09-19 15:00 2347在讲述文件映 ... -
Berkeley DB 由浅入深【转自架构师杨建】
2012-09-19 15:00 1968在网上看到不少介绍Berkeley DB的文章,几乎 ... -
linux 多线程编程
2012-09-19 15:00 1521进程与线程 进程是程序执行时的一个实例 ... -
pthread_cond_wait()
2012-09-25 10:13 840/************pthread_cond_w ... -
linux下创建守护进程(daemon process)代码
2012-09-18 13:47 1654#include <stdio.h> ... -
dup and dup2的剖析
2012-09-18 13:35 671dup和dup2都可用来复制一个现存的文件描述符,使两个 ... -
C语言系统资源控制(getrlimit && setrlimit)
2012-09-18 11:52 988每一个进程都有自己的一组资源限制,在(*)inux系统中 ... -
UNIX缓冲机制
2012-09-18 11:11 1010某日一朋友写了一个HELL ...
相关推荐
为了避免内存碎片导致的系统崩溃,开发过程中应充分测试系统在长时间运行下的表现,尤其是在高负载和复杂内存操作场景下。通过模拟实际工作负载的长时间测试,可以尽早发现内存碎片问题,并采取相应的优化措施,确保...
为了避免内存碎片的产生,程序员可以在编译程序和链接程序中为结构并集、数组和标量方面的数据分配内存,或者在运行时间使用诸如 malloc() 调用命令动态地分配内存。编译程序了解数据寿命,因此可以使数据以后进先出...
这种方式可以有效避免内存碎片。 - **运行时间分配**:通过如`malloc()`等函数动态分配内存,这种方式容易产生内存碎片,因为分配的时机和大小不确定。 #### 六、案例分析 假设一个系统有5MB的空闲内存,但是最大的...
本篇文章将深入探讨内存碎片的产生机制、影响以及如何通过编程实践来避免和解决这个问题。 首先,我们来理解内存碎片的定义。内存碎片是指在计算机内存中,由于频繁的分配和释放操作,使得可用的内存空间被分割成...
在诸多影响系统性能的因素中,内存碎片整理显得尤为重要,因为它直接影响着计算机运行速度和效率。内存碎片整理工具就是为了解决这一问题而应运而生的。 内存碎片整理工具的工作原理在于对内存中的碎片进行重新组织...
内存管理是计算机编程中的核心部分,特别是在C++中,它涉及到资源的分配和释放,而内存碎片问题则是内存管理中的常见挑战。线程局部存储(TLS,Thread Local Storage)是一种有效的优化策略,尤其是在多线程环境中,...
通过使用内存池技术,开发者可以更好地控制内存分配和释放过程,减少系统资源消耗,避免内存碎片,提升程序整体性能。在系统资源受限或者性能要求较高的应用场景中,使用内存池是非常必要和有效的。
内存碎片分为内部碎片和外部碎片。内部碎片是分配给进程的内存比实际需要的大,多余的那部分无法再利用。外部碎片则是多个小的空闲内存块无法合并成一个大块,导致大的内存需求无法满足。外部碎片可以通过内存整理...
在.NET环境中,内存池可以帮助开发者更高效地管理内存,避免内存碎片,并提高应用程序的性能。 内存碎片是由于频繁的内存分配和释放导致内存空间不连续,从而影响程序运行效率的现象。在传统的内存管理方式中,比如...
### 如何避免内存碎片化 为了减少内存碎片化的影响,可以采取以下几种策略: 1. **使用特定的内存分配器**:有些内存分配器专门设计用于减少内存碎片化。例如,可以使用分层内存分配器或定制的分配器来管理不同...
通过内存池,应用程序可以避免内存碎片化问题,并且通过减少内存分配和释放的次数来提高整体性能。内存池特别适用于那些内存分配模式可预测、频繁创建和销毁相同大小对象的应用场景,比如服务器程序、游戏开发和实时...
同时,合理地使用`Alloc`和`Free`以保持内存池的高效运作,避免内存碎片的产生,是提高程序性能的重要步骤。通过理解并熟练运用这些内存管理技术,开发者能够编写出更加健壮、高效的易语言程序。
2. 内存块的大小:我们可以根据实际情况选择合适的内存块大小,以避免内存碎片的出现。 3. 内存释放机制:我们可以使用动态调整机制来释放内存,以避免内存泄露。 内存池的实现: 在实现内存池时,我们可以使用...
内存分配的目标是确保每个进程都能获得足够的内存空间执行任务,同时避免内存碎片,提高内存利用率。在传统的操作系统中,内存分配通常分为静态分配和动态分配两种方式。 1. 静态分配:在程序编译时就确定了内存...
- Mmap映射区域操作相关函数:`mmap()`和`munmap()`用于将文件或匿名内存映射到进程的地址空间,这种分配方式常用于大块内存的分配,因为它可以避免内存碎片。 3. Ptmalloc内存管理概述 Ptmalloc是Glibc中的多线程...
在操作系统中,内存管理的主要目标是确保程序能够高效地运行,同时避免内存碎片和其他性能问题。本题主要关注的是通过代码来模拟内存管理的过程。 在“模拟内存管理”的试题中,我们可能会遇到以下几个核心概念: ...
3. **避免内存碎片**:虽然这不是直接的内存释放问题,但有效的内存管理应尽量减少内存碎片,以提高内存的整体利用率。 4. **使用智能指针**:在支持智能指针的编程语言中(如C++的`shared_ptr`和`unique_ptr`),...
然而,在使用StringBuilder时,开发者需要注意避免内存碎片对性能的影响。本文将对StringBuilder的内存碎片对性能的影响进行详细的介绍,并提供解决方案。 知识点1:StringBuilder的内部实现 StringBuilder内部是由...
这类软件的主要作用是通过算法有效地释放和重新组织内存资源,避免内存碎片的产生,从而让计算机运行更加流畅。 内存,即RAM(随机存取存储器),是计算机中临时存储数据的地方,用于运行应用程序和处理数据。当...