s_i*_*bhu 56 c memory size allocation dynamic
有没有办法在C中找出动态分配内存的大小?
例如,之后
char* p = malloc (100);
Run Code Online (Sandbox Code Playgroud)
有没有办法找出与之相关的内存大小p?
ars*_*ars 44
没有标准的方法来查找此信息.但是,某些实现提供msize了执行此操作的功能.例如:
但请记住,malloc将分配所请求大小的最小值,因此您应检查实现的msize变量是否实际返回对象的大小或实际在堆上分配的内存.
Art*_*ius 11
C心态是为程序员提供工具来帮助他完成工作,而不是提供改变其工作性质的抽象.如果以牺牲性能限制为代价,C还会尝试避免使事情变得更容易/更安全.
您可能想要对内存区域执行的某些操作仅需要区域开头的位置.这样的事情包括使用以null结尾的字符串,操作区域的前n个字节(如果已知该区域至少这么大),等等.
基本上,跟踪区域的长度是额外的工作,如果C自动执行,它有时会不必要地执行它.
许多库函数(例如fread())需要指向区域开头的指针,以及该区域的大小.如果您需要区域大小,则必须跟踪它.
是的,malloc()实现通常会跟踪区域的大小,但是它们可以间接地执行此操作,或者将其四舍五入到某个值,或者根本不保留它.即使他们支持它,与自己跟踪它相比,以这种方式找到大小可能会很慢.
如果您需要一个知道每个区域有多大的数据结构,C可以为您做到这一点.只需使用一个结构来跟踪区域的大小以及指向该区域的指针.
每个告诉你不可能的人在技术上都是正确的(最好的正确类型)。
出于工程原因,依靠 malloc 子系统准确地告诉您已分配块的大小是一个坏主意。为了让自己相信这一点,假设您正在编写一个包含多个不同内存分配器的大型应用程序——也许您malloc在一部分中使用原始 libc ,operator new在另一部分中使用C++ ,然后在另一部分中使用某些特定的 Windows API。所以你有各种各样的void*飞来飞去。编写一个可以处理任何这些问题void*的函数是不可能的,除非您能以某种方式从指针的值中知道它来自哪个堆。
因此,您可能希望使用一些约定来包装程序中的每个指针,以指示指针来自何处(以及需要返回到何处)。例如,在 C++ 中,我们称之为std::unique_ptr<void>(对于需要operator delete'dstd::unique_ptr<void, D>的指针)或(对于需要通过其他机制返回的指针D)。如果你愿意,你可以在 C 中做同样的事情。无论如何,一旦您将指针封装在更大的更安全的对象中,这只是一小步struct SizedPtr { void *ptr; size_t size; },然后您就再也不需要担心分配的大小了。
然而。
您可能有正当理由想知道分配的实际基础大小,这也是有充分理由的。例如,也许您正在为您的应用程序编写一个分析工具,它将报告每个子系统使用的实际内存量,而不仅仅是程序员认为他正在使用的内存量。如果您的每个 10 字节分配在幕后秘密使用 16 字节,那么知道这一点很高兴!(当然也会有其他开销,您不会以这种方式衡量。但是还有其他工具可以完成这项工作。)或者您可能只是在调查realloc平台上的行为。或者,您可能想“汇总”不断增长的分配的容量以避免过早未来重新分配。例子:
SizedPtr round_up(void *p) {
size_t sz = portable_ish_malloced_size(p);
void *q = realloc(p, sz); // for sanitizer-cleanliness
assert(q != NULL && portable_ish_malloced_size(q) == sz);
return (SizedPtr){q, sz};
}
bool reserve(VectorOfChar *v, size_t newcap) {
if (v->sizedptr.size >= newcap) return true;
char *newdata = realloc(v->sizedptr.ptr, newcap);
if (newdata == NULL) return false;
v->sizedptr = round_up(newdata);
return true;
}
Run Code Online (Sandbox Code Playgroud)
要获取直接从 libc malloc 返回的非空指针后面的分配大小- 不是从自定义堆,也不是指向对象的中间 - 您可以使用以下特定于操作系统的 API,我为方便起见,已捆绑为“便携式”包装器功能。如果您发现此代码不起作用的常见系统,请发表评论,我会尽力修复它!
#if defined(__linux__)
// https://linux.die.net/man/3/malloc_usable_size
#include <malloc.h>
size_t portable_ish_malloced_size(const void *p) {
return malloc_usable_size((void*)p);
}
#elif defined(__APPLE__)
// https://www.unix.com/man-page/osx/3/malloc_size/
#include <malloc/malloc.h>
size_t portable_ish_malloced_size(const void *p) {
return malloc_size(p);
}
#elif defined(_WIN32)
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize
#include <malloc.h>
size_t portable_ish_malloced_size(const void *p) {
return _msize((void *)p);
}
#else
#error "oops, I don't know this system"
#endif
#include <stdio.h>
#include <stdlib.h> // for malloc itself
int main() {
void *p = malloc(42);
size_t true_length = portable_ish_malloced_size(p);
printf("%zu\n", true_length);
}
Run Code Online (Sandbox Code Playgroud)
测试:
_msizemalloc_usable_sizemalloc_sizemalloc和原生 libc malloc_size)USE_DL_PREFIX这是我看到的创建标记指针以存储大小和地址的最佳方法。所有指针函数仍将按预期工作:
被盗:https : //stackoverflow.com/a/35326444/638848
您还可以为malloc实现包装器,并在malloc返回的指针之前自由添加标签(如分配的大小和其他元信息)。实际上,这是c ++编译器使用对虚拟类的引用标记对象的方法。这是一个工作示例:
Run Code Online (Sandbox Code Playgroud)#include <stdlib.h> #include <stdio.h> void * my_malloc(size_t s) { size_t * ret = malloc(sizeof(size_t) + s); *ret = s; return &ret[1]; } void my_free(void * ptr) { free( (size_t*)ptr - 1); } size_t allocated_size(void * ptr) { return ((size_t*)ptr)[-1]; } int main(int argc, const char ** argv) { int * array = my_malloc(sizeof(int) * 3); printf("%u\n", allocated_size(array)); my_free(array); return 0; }与具有大小和指针的结构相比,此方法的优势
Run Code Online (Sandbox Code Playgroud)struct pointer { size_t size; void *p; };就是您只需要替换malloc和free调用即可。所有其他指针操作都不需要重构。