C二进制达到1.2G内存限制

719*_*016 0 c memory 64-bit memory-management out-of-memory

我正在处理一个C程序,该程序从一个文件中读入,每行大约有60个字符,并通过在读取文件时请求更多内存来在内存中分配字符串.在每次malloc 请求之后,它会检查函数OOM()是否有请求为了更多的记忆成功.

我已经使用越来越大的输入文件测试了程序,并且 在程序运行时查看命令时内存使用率达到1.2G时或多或少地OOM()报告.这是在64位Linux机器上,有更多的内存可用.输出来自:"Out of memory"topfile /my/binary/program

ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么它达到了1.2G的限制?我记得我的系统管理员曾经说某些二进制文件只能使用高达1.2G,这恰恰就是我在这里看到的.

当我qsub在保留50GB内存的同一64位Linux SGE网格的节点上运行相同的执行时,它会报告"Out of memory"以及以下SGE日志内存占用:

Max vmem         = 2.313G
Run Code Online (Sandbox Code Playgroud)

有什么想法为什么程序达到这个内存限制?是否有任何编译标志我应该知道哪些可能导致/解决这个问题?

在下面找到当前的相关标志Makefile:

CC = gcc
CFLAGS = -Wall -O3 -funroll-loops -DNDEBUG -fomit-frame-pointer -std=gnu99 -msse2 -Wno-unused-function -Wno-unused-result
CFLAGSSFMT = -msse2 -DHAVE_SSE2 -O9 -finline-functions -fomit-frame-pointer \
-DNDEBUG -fno-strict-aliasing --param max-inline-insns-single=1800 -std=c99
LD = ld
LDFLAGS =  -lm -lc -lblas -llapack
INCFLAGS = 
DEFINES = -D_GNU_SOURCE -DUSE_BLAS
Run Code Online (Sandbox Code Playgroud)

一些相关的代码belo:w

mystring.h:

#ifndef _MYSTRING_H_
#define _MYSTRING_H_

struct __mystring_struct {
   char * string;
   int len, maxlen;
};
typedef struct __mystring_struct * Mystring;
#define Mystring_size sizeof(struct __mystring_struct)

Mystring new_mystring (const int len);
void free_mystring (Mystring string);
void append_char_to_mystring ( const char c, Mystring string);
char * cstring_of_mystring(const Mystring string);
Mystring mystring_of_cstring (const char * str);
#endif
Run Code Online (Sandbox Code Playgroud)

mystring.c:

#include <string.h>
#include "mystring.h"

#define OOM(A) { if (NULL==(A) ){fputs("Out of memory\n",stderr); exit(EXIT_FAILURE);} }
static void check_is_mystring (const Mystring string);
static void double_length_of_mystring ( Mystring string);
Run Code Online (Sandbox Code Playgroud)

稍后的:

static void double_length_of_mystring (Mystring string){
   char * new_mem;
   check_is_mystring(string);

   new_mem = malloc(string->maxlen * 2 * sizeof(char)); OOM(new_mem);
   memcpy (new_mem,string->string,string->len * sizeof(char));
   free(string->string);
   string->string = new_mem;
   string->maxlen *= 2;

   check_is_mystring (string);
}
Run Code Online (Sandbox Code Playgroud)

Sum*_*uma 6

它似乎int用于保持字符串的大小.在GCC(以及大多数其他PC平台编译器)中,即使在64b平台上,这种类型也是32b.你应该使用size_t.

分配失败的机制如下:

  • 1.2 GB~ = 1288490189
  • 2*1.2 GB~ = 2576980378,超过2 ^ 31(2147483648),溢出后得到-1717986918的第二补码算法
  • 调用时malloc,-1717986918符号扩展为64 b,然后转换为无符号64b,这将给你2 ^ 64 - 1717986918,这只是略低于2 ^ 64,并且肯定比系统中的内存更多.

  • @AndrewHenle:负的`int32`符号扩展为64位值,然后转换为`size_t`?这将是一个非常大的数字,这可能会导致`maloc`返回"null". (4认同)
  • @EOF:看起来他每次都会将分配大小加倍.因此从1.2到2.4GB将是一个问题 (2认同)