我正在编写代码来使用名为 SCIP 的库(解决优化问题)。库本身可以通过两种方式进行编译:创建一组 .a 文件,然后创建二进制文件,或者创建一组共享对象。在这两种情况下,SCIP 都是使用它自己的、相当大的 Makefile 进行编译的。
我有两种实现,一种是使用 .a 文件进行编译(我将其称为程序 1),另一种是与共享对象的链接(我将其称为程序 2)。程序 1 使用 SCIP 提供的 makefile 进行编译,而程序 2 使用我自己的、简单得多的 makefile 进行编译。
我遇到的行为发生在 SCIP 代码中,而不是我编写的代码中。代码摘录如下:
void* BMSallocMemory_call(size_t size)
{
void* ptr;
size = MAX(size, 1);
ptr = malloc(size);
// This is where I call gdb print statements.
if( ptr == NULL )
{
printf("ERROR - unable to allocate memory for a SCIP*.\n");
}
return ptr;
}
void SCIPcreate(SCIP** A)
{
*A = (SCIP*)BMSallocMemory_call(sizeof(**(A)))
.
.
.
}
如果我在 gdb 中调试此代码,并单步执行
BMSallocMemory_call()
以查看发生了什么,并查看 *((SCIP*)(ptr))
的内容,我会得到以下输出:
程序1 gdb 输出:
289 size = MAX(size, 1);
(gdb) step
284 {
(gdb)
289 size = MAX(size, 1);
(gdb)
290 ptr = malloc(size);
(gdb) print ptr
$1 = <value optimised out>
(gdb) step
292 if( ptr == NULL )
(gdb) print ptr
$2 = <value optimised out>
(gdb) step
290 ptr = malloc(size);
(gdb) print ptr
$3 = (void *) 0x8338448
(gdb) print *((SCIP*)(ptr))
$4 = {mem = 0x0, set = 0x0, interrupt = 0x0, dialoghdlr = 0x0, totaltime = 0x0, stat = 0x0, origprob = 0x0, eventfilter = 0x0, eventqueue = 0x0, branchcand = 0x0, lp = 0x0, nlp = 0x0, relaxation = 0x0, primal = 0x0, tree = 0x0, conflict = 0x0, cliquetable = 0x0, transprob = 0x0, pricestore = 0x0, sepastore = 0x0, cutpool = 0x0}
程序2 gdb输出:
289 size = MAX(size, 1);
(gdb) step
290 ptr = malloc(size);
(gdb) print ptr
$1 = (void *) 0xb7fe450c
(gdb) print *((SCIP*)(ptr))
$2 = {mem = 0x1, set = 0x8232360, interrupt = 0x1, dialoghdlr = 0xb7faa6f8, totaltime = 0x0, stat = 0xb7fe45a0, origprob = 0xb7fe4480, eventfilter = 0xfffffffd, eventqueue = 0x1, branchcand = 0x826e6a0, lp = 0x8229c20, nlp = 0xb7fdde80, relaxation = 0x822a0d0, primal = 0xb7f77d20, tree = 0xb7fd0f20, conflict = 0xfffffffd, cliquetable = 0x1, transprob = 0x8232360, pricestore = 0x1, sepastore = 0x822e0b8, cutpool = 0x0}
我能想到的唯一原因是,在程序 1 或 SCIP 的 makefile 中,有某种选项强制 malloc 初始化它分配的内存。我必须了解为什么该结构是在编译实现中初始化的,而不是在共享对象实现中初始化的。
我怀疑差异与这两个程序的构建方式有关。
malloc
不会初始化它分配的内存。偶然情况下,你取回的记忆可能会被零填满。例如,与已经运行了一段时间并分配/释放内存的程序相比,刚刚启动的程序更有可能从 malloc
获取零填充内存。
编辑 您可能会发现以下过去感兴趣的问题:
malloc 内存的初始化可能取决于实现。出于性能原因,实现可以不这样做,但它们可以初始化内存,例如在调试模式下。
还有一点要注意。即使未初始化的内存也可能包含零。
在Linux上,根据这个线程,内存第一次交给应用程序时将被零填充。因此,如果您对
malloc()
的调用导致程序的堆增长,“新”内存将被零填充。
验证的一种方法当然是从您的例程中单步执行 into
malloc()
,这应该可以清楚地表明它是否包含直接初始化内存的代码。