如果请求超过可用物理内存(即不使用交换),如何使malloc/calloc失败

如果请求超过可用物理内存(即不使用交换),如何使malloc/calloc失败,c,linux,malloc,C,Linux,Malloc,malloc/calloc显然使用交换空间来满足超出可用内存的请求。由于磁盘使用指示灯一直亮着,这几乎使系统挂起。在这件事发生在我身上之后,我不知道为什么,我写了下面的5行测试程序来检查这确实是系统挂起的原因 /* --- test how many bytes can be malloc'ed successfully --- */ #include <stdio.h> #include <stdlib.h> int main ( int argc, char *arg

malloc/calloc显然使用交换空间来满足超出可用内存的请求。由于磁盘使用指示灯一直亮着,这几乎使系统挂起。在这件事发生在我身上之后,我不知道为什么,我写了下面的5行测试程序来检查这确实是系统挂起的原因

/* --- test how many bytes can be malloc'ed successfully --- */
#include <stdio.h>
#include <stdlib.h>
int main ( int argc, char *argv[] ) {
  unsigned int nmalloc = (argc>1? atoi(argv[1]) : 10000000 ),
               size    = (argc>2? atoi(argv[2]) : (0) );
  unsigned char *pmalloc = (size>0? calloc(nmalloc,size):malloc(nmalloc));
  fprintf( stdout," %s malloc'ed %d elements of %d bytes each.\n",
    (pmalloc==NULL? "UNsuccessfully" : "Successfully"),
    nmalloc, (size>0?size:1) );
  if ( pmalloc != NULL ) free(pmalloc);
  } /* --- end-of-function main() --- */
/*--测试可以成功删除多少字节--*/
#包括
#包括
int main(int argc,char*argv[]){
unsigned int nmalloc=(argc>1?atoi(argv[1]):10000000),
大小=(argc>2?原子(argv[2]):(0));
无符号字符*pmalloc=(大小>0?calloc(nmalloc,大小):malloc(nmalloc));
fprintf(标准输出,“%s malloc'ed%d个元素,每个元素有%d个字节。\n”,
(pmalloc==NULL?“未成功”:“成功”),
nmalloc(尺寸>0?尺寸:1));
如果(pmalloc!=NULL)自由(pmalloc);
}/*--函数main()结束--*/
如果两个命令行参数的乘积超过物理内存,那么这确实会挂起系统。最简单的解决方案是malloc/calloc自动失败。更难且不可移植的是编写一个小包装器,使popen()是一个空闲命令,解析输出,并且只有在可用的“空闲”内存可以满足请求的情况下才调用malloc/calloc,可能内置了一点安全系数

有没有更简单、更便携的方法来实现这一点?(显然与这个问题类似,但我希望得到某种“是”的答案。)

E-d-i-t
------------

决定遵循Tom的/proc/meminfo建议。也就是说,与popen()的“free”不同,只需直接解析现有且易于解析的/proc/meminfo文件。然后是表单的单行宏

#定义noswapmalloc(n)((n)<1000l*memfree(NULL)/2?malloc(n):NULL)

完成工作。如下所示,memfree()并不像我希望的那样可移植,但如果需要,可以轻松透明地被更好的解决方案取代,而现在还没有

#include <stdio.h>
#include <stdlib.h>
#define _GNU_SOURCE                     /* for strcasestr() in string.h */
#include <string.h>
char    *strcasestr();                  /* non-standard extension */

/* ==========================================================================
 * Function:    memfree ( memtype )
 * Purpose:     return number of Kbytes of available memory
 *              (as reported in /proc/meminfo)
 * --------------------------------------------------------------------------
 * Arguments:   memtype (I)     (char *) to null-terminated, case-insensitive
 *                              (sub)string matching first field in
 *                              /proc/meminfo (NULL uses MemFree)
 * --------------------------------------------------------------------------
 * Returns:     ( int )         #Kbytes of memory, or -1 for any error
 * --------------------------------------------------------------------------
 * Notes:       o
 * ======================================================================= */
/* --- entry point --- */
int     memfree ( char *memtype ) {
  /* ---
   * allocations and declarations
   * ------------------------------- */
  static char memfile[99] = "/proc/meminfo"; /* linux standard */
  static char deftype[99] = "MemFree";  /* default if caller passes null */
  FILE  *fp = fopen(memfile,"r");       /* open memfile for read */
  char  memline[999];                   /* read memfile line-by-line */
  int   nkbytes = (-1);                 /* #Kbytes, init for error */
  /* ---
   * read memfile until line with desired memtype found
   * ----------------------------------------------------- */
  if ( memtype == NULL ) memtype = deftype; /* caller wants default */
  if ( fp == NULL ) goto end_of_job;    /* but we can't get it */
  while ( fgets(memline,512,fp)         /* read next line */
  !=      NULL ) {                      /* quit at eof (or error) */
    if ( strcasestr(memline,memtype)    /* look for memtype in line */
    !=   NULL ) {                       /* found line with memtype */
      char *delim = strchr(memline,':'); /* colon following MemType */
      if ( delim != NULL )              /* NULL if file format error? */
        nkbytes = atoi(delim+1);        /* num after colon is #Kbytes */
      break; }                          /* no need to read further */
    } /* --- end-of-while(fgets()!=NULL) --- */
  end_of_job:                           /* back to caller with nkbytes */
    if ( fp != NULL ) fclose(fp);       /* close /proc/meminfo file */
    return ( nkbytes );                 /* and return nkbytes to caller */
  } /* --- end-of-function memfree() --- */

#if defined(MEMFREETEST)
int     main ( int argc, char *argv[] ) {
  char  *memtype = ( argc>1? argv[1] : NULL );
  int   memfree();
  printf ( " memfree(\"%s\") = %d Kbytes\n Have a nice day.\n",
        (memtype==NULL?" ":memtype), memfree(memtype) );
  } /* --- end-of-function main() --- */
#endif
#包括
#包括
#为string.h中的strcasestr()定义_GNU_SOURCE/**/
#包括
char*strcasestr();/*非标准扩展*/
/* ==========================================================================
*功能:memfree(memtype)
*用途:返回可用内存的KB数
*(如/proc/meminfo中所述)
* --------------------------------------------------------------------------
*参数:memtype(I)(char*)以null结尾,不区分大小写
*(子)字符串匹配中的第一个字段
*/proc/meminfo(NULL使用MemFree)
* --------------------------------------------------------------------------
*返回:(int)#Kbytes内存,或任何错误返回-1
* --------------------------------------------------------------------------
*注:o
* ======================================================================= */
/*---入口点--*/
int memfree(char*memtype){
/* ---
*分配和申报
* ------------------------------- */
静态char memfile[99]=“/proc/meminfo”;/*linux标准*/
静态char deftype[99]=“MemFree”/*如果调用方传递null,则为默认值*/
FILE*fp=fopen(memfile,“r”);/*打开memfile进行读取*/
char memline[999];/*逐行读取memfile*/
int-nkbytes=(-1);/*#Kbytes,init表示错误*/
/* ---
*读取memfile,直到找到具有所需memtype的行
* ----------------------------------------------------- */
如果(memtype==NULL)memtype=deftype;/*调用者想要默认值*/
如果(fp==NULL)转到\u作业的\u;/*的\u,但我们无法获取它*/
而(fgets(memline,512,fp)/*读取下一行*/
!=NULL){/*在eof时退出(或错误)*/
if(strcasestr(memline,memtype)/*在行中查找memtype*/
!=NULL){/*找到了memtype为的行*/
char*delim=strchr(memline,:');/*MemType后面的冒号*/
如果(delim!=NULL)/*NULL文件格式错误*/
冒号后的nkbytes=atoi(delim+1);/*num为#Kbytes*/
break;}/*无需进一步阅读*/
}/*---时间结束(fgets()!=NULL)--*/
结束\u作业:/*返回到具有NK字节的调用者*/
如果(fp!=NULL)fclose(fp);/*关闭/proc/meminfo文件*/
返回(nkbytes);/*并将nkbytes返回给调用者*/
}/*--函数memfree()的结尾--*/
#如果已定义(MEMFREETEST)
int main(int argc,char*argv[]){
char*memtype=(argc>1?argv[1]:NULL);
int memfree();
printf(“memfree(\%s\”)=%d千字节\n祝您今天愉快。\n“,
(memtype==NULL?“:memtype),memfree(memtype));
}/*--函数main()结束--*/
#恩迪夫
malloc/calloc显然使用交换空间来满足超出可用内存的请求

嗯,没有

Malloc/calloc使用虚拟内存。“虚拟”意味着它不是真实的——它是一种由谎言和谎言构成的人为的幻觉。你的整个过程都是建立在这些人为构造的幻觉之上的——线程是一个虚拟CPU,套接字是一个虚拟网络连接,C语言实际上是一个“C抽象机”的规范,进程是一个虚拟计算机(实现了这些语言的抽象机)

你不应该看魔法幕后面。你不应该知道物理内存的存在。系统没有挂起-只是错觉比较慢,但这很好,因为C抽象机没有说明任何东西需要多长时间,也没有提供任何性能保证

更重要的是,;
#include <stdio.h>
#include <stdlib.h>
int main ( int argc, char *argv[] ) {
  /* These three lines were added */
  void* tmp = calloc(1000, 1); /* force initialization */
  printf("Allocated 1000 bytes at %p\n", tmp);
  free(tmp);
  /* The rest is unchanged */
  unsigned int nmalloc = (argc>1? atoi(argv[1]) : 10000000 ),
               size    = (argc>2? atoi(argv[2]) : (0) );
  unsigned char *pmalloc = (size>0? calloc(nmalloc,size):malloc(nmalloc));
  fprintf( stdout," %s malloc'ed %d elements of %d bytes each.\n",
    (pmalloc==NULL? "UNsuccessfully" : "Successfully"),
    nmalloc, (size>0?size:1) );
  if ( pmalloc != NULL ) free(pmalloc);
}
$ gcc -Og -ggdb -Wall -o mall mall.c

$ # A simple malloc completes instantly without page faults
$ /usr/bin/time ./mall 4000000000
Allocated 1000 bytes at 0x55b94ff56260
 Successfully malloc'ed -294967296 elements of 1 bytes each.
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 1600maxresident)k
0inputs+0outputs (0major+61minor)pagefaults 0swaps

$ # Unless we tell malloc to initialise memory
$ MALLOC_PERTURB_=35 /usr/bin/time ./mall 4000000000
Allocated 1000 bytes at 0x5648c2436260
 Successfully malloc'ed -294967296 elements of 1 bytes each.
0.19user 1.23system 0:01.43elapsed 99%CPU (0avgtext+0avgdata 3907584maxresident)k
0inputs+0outputs (0major+976623minor)pagefaults 0swaps

# Same, with calloc. No page faults, instant completion.
$ /usr/bin/time ./mall 1000000000 4
Allocated 1000 bytes at 0x55e8257bb260
 Successfully malloc'ed 1000000000 elements of 4 bytes each.
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 1656maxresident)k
0inputs+0outputs (0major+62minor)pagefaults 0swaps

$ # Again, setting the magic malloc config variable changes everything
$ MALLOC_PERMUTE_=35 /usr/bin/time ./mall 1000000000 4
Allocated 1000 bytes at 0x5646f391e260
 Successfully malloc'ed 1000000000 elements of 4 bytes each.
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 1656maxresident)k
0inputs+0outputs (0major+62minor)pagefaults 0swaps