valgrind:多次 std::vector::resize 调用
valgrind: Multiple std::vector::resize calls
我一直在追踪大型 C++ 代码库中的一个差一问题。出于某种原因,我无法理解以下 Valgrind 行为。有人可以在这里阐明一下吗?
代码是:
% cat foo.cxx
#include <cstring>
#include <string>
#include <vector>
int main() {
std::vector<char> v;
#ifdef RESIZE9
v.resize(9);
#endif
v.resize(10);
std::string s(10, 'x');
std::strcpy(&v[0], s.c_str());
return 0;
}
这是预期的 Valgrind 输出:
% g++ foo.cxx && valgrind ./a.out
==21886== Memcheck, a memory error detector
==21886== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21886== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==21886== Command: ./a.out
==21886==
==21886== Invalid write of size 1
==21886== at 0x4838DD7: strcpy (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==21886== by 0x1092CA: main (in /tmp/a.out)
==21886== Address 0x4d84c8a is 0 bytes after a block of size 10 alloc'd
==21886== at 0x4835DEF: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==21886== by 0x109BCD: __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) (in /tmp/a.out)
==21886== by 0x109AD5: std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) (in /tmp/a.out)
==21886== by 0x109997: std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) (in /tmp/a.out)
==21886== by 0x1095E8: std::vector<char, std::allocator<char> >::_M_default_append(unsigned long) (in /tmp/a.out)
==21886== by 0x1093CC: std::vector<char, std::allocator<char> >::resize(unsigned long) (in /tmp/a.out)
==21886== by 0x10926A: main (in /tmp/a.out)
==21886==
==21886==
==21886== HEAP SUMMARY:
==21886== in use at exit: 0 bytes in 0 blocks
==21886== total heap usage: 2 allocs, 2 frees, 72,714 bytes allocated
==21886==
==21886== All heap blocks were freed -- no leaks are possible
==21886==
==21886== For counts of detected and suppressed errors, rerun with: -v
==21886== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
但现在考虑以下问题:
% g++ -DRESIZE9 foo.cxx && valgrind ./a.out
==21904== Memcheck, a memory error detector
==21904== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21904== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==21904== Command: ./a.out
==21904==
==21904==
==21904== HEAP SUMMARY:
==21904== in use at exit: 0 bytes in 0 blocks
==21904== total heap usage: 3 allocs, 3 frees, 72,731 bytes allocated
==21904==
==21904== All heap blocks were freed -- no leaks are possible
==21904==
==21904== For counts of detected and suppressed errors, rerun with: -v
==21904== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
系统是 Debian/10.9,其中:
% g++ --version
g++ (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
和
% valgrind --version
valgrind-3.14.0
虽然我无法确认这是一个完整(跨平台)'solution',但添加一行以显示实际的容量 调整大小操作后的矢量可能会有所启发:
#include <cstring>
#include <string>
#include <vector>
#include <iostream>
//#define RESIZE9 1
int main()
{
std::vector<char> v;
#ifdef RESIZE9
v.resize(9);
#endif
v.resize(10);
std::cout << v.capacity() << std::endl; // Show the actual allocated size
std::string s(10, 'x');
std::strcpy(&v[0], s.c_str());
return 0;
}
运行 此代码 原样 (Visual Studio, MSVC, Windows 10, 64-bit) 显示容量为 10
(意料之中)。但是,当取消注释 #define RESIZE9 1
行时,显示的容量(在 两次 调整大小调用之后)是 13
.
添加额外的容量,我相信,在标准的要求之内:只要新分配的 vector 有 足够的容量 来满足新的大小,没有什么是坏的。分配 4 个额外字节(而不是一个字节)最有可能优化内存管理。
我一直在追踪大型 C++ 代码库中的一个差一问题。出于某种原因,我无法理解以下 Valgrind 行为。有人可以在这里阐明一下吗?
代码是:
% cat foo.cxx
#include <cstring>
#include <string>
#include <vector>
int main() {
std::vector<char> v;
#ifdef RESIZE9
v.resize(9);
#endif
v.resize(10);
std::string s(10, 'x');
std::strcpy(&v[0], s.c_str());
return 0;
}
这是预期的 Valgrind 输出:
% g++ foo.cxx && valgrind ./a.out
==21886== Memcheck, a memory error detector
==21886== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21886== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==21886== Command: ./a.out
==21886==
==21886== Invalid write of size 1
==21886== at 0x4838DD7: strcpy (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==21886== by 0x1092CA: main (in /tmp/a.out)
==21886== Address 0x4d84c8a is 0 bytes after a block of size 10 alloc'd
==21886== at 0x4835DEF: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==21886== by 0x109BCD: __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) (in /tmp/a.out)
==21886== by 0x109AD5: std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) (in /tmp/a.out)
==21886== by 0x109997: std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) (in /tmp/a.out)
==21886== by 0x1095E8: std::vector<char, std::allocator<char> >::_M_default_append(unsigned long) (in /tmp/a.out)
==21886== by 0x1093CC: std::vector<char, std::allocator<char> >::resize(unsigned long) (in /tmp/a.out)
==21886== by 0x10926A: main (in /tmp/a.out)
==21886==
==21886==
==21886== HEAP SUMMARY:
==21886== in use at exit: 0 bytes in 0 blocks
==21886== total heap usage: 2 allocs, 2 frees, 72,714 bytes allocated
==21886==
==21886== All heap blocks were freed -- no leaks are possible
==21886==
==21886== For counts of detected and suppressed errors, rerun with: -v
==21886== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
但现在考虑以下问题:
% g++ -DRESIZE9 foo.cxx && valgrind ./a.out
==21904== Memcheck, a memory error detector
==21904== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21904== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==21904== Command: ./a.out
==21904==
==21904==
==21904== HEAP SUMMARY:
==21904== in use at exit: 0 bytes in 0 blocks
==21904== total heap usage: 3 allocs, 3 frees, 72,731 bytes allocated
==21904==
==21904== All heap blocks were freed -- no leaks are possible
==21904==
==21904== For counts of detected and suppressed errors, rerun with: -v
==21904== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
系统是 Debian/10.9,其中:
% g++ --version
g++ (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
和
% valgrind --version
valgrind-3.14.0
虽然我无法确认这是一个完整(跨平台)'solution',但添加一行以显示实际的容量 调整大小操作后的矢量可能会有所启发:
#include <cstring>
#include <string>
#include <vector>
#include <iostream>
//#define RESIZE9 1
int main()
{
std::vector<char> v;
#ifdef RESIZE9
v.resize(9);
#endif
v.resize(10);
std::cout << v.capacity() << std::endl; // Show the actual allocated size
std::string s(10, 'x');
std::strcpy(&v[0], s.c_str());
return 0;
}
运行 此代码 原样 (Visual Studio, MSVC, Windows 10, 64-bit) 显示容量为 10
(意料之中)。但是,当取消注释 #define RESIZE9 1
行时,显示的容量(在 两次 调整大小调用之后)是 13
.
添加额外的容量,我相信,在标准的要求之内:只要新分配的 vector 有 足够的容量 来满足新的大小,没有什么是坏的。分配 4 个额外字节(而不是一个字节)最有可能优化内存管理。