如果我有这样的功能:
void bla(int size) {
while(b){
char tmp[size];
......
}
}
Run Code Online (Sandbox Code Playgroud)
tmp在while循环的每次迭代中被释放,对吗?
如果我写这个函数:
void bla(int size) {
while(b){
char* tmp = alloca(size);
......
}
}
Run Code Online (Sandbox Code Playgroud)
tmp在范围结束时或功能结束时被释放?
较旧的K&R(第二版)和其他我读过的C语言文本讨论了动态内存分配器的实现方式,malloc()
并且free()
通常还提及有关数据类型对齐限制的内容.显然,某些计算机硬件体系结构(CPU,寄存器和内存访问)限制了如何存储和处理某些值类型.例如,可能要求long
必须从4的倍数地址开始存储4字节()整数.
主要平台(英特尔和AMD,SPARC,Alpha)对内存分配和内存访问有什么限制(如果有的话),还是可以安全地忽略在特定地址边界上对齐内存分配?
对于我的一个项目,我正在从头开始编写一些STL容器(我有我的理由).由于我如此密切地模仿STL的功能和接口,我正在尽力遵守策略"如果它与标准构造具有相同的名称,它将尽可能符合标准."
所以,当然我的容器将allocator作为模板参数,这非常好,因为它允许一些自定义分配方案.关于我的问题.
所述std::allocator
接口从对象分离结构的存储器分配.同样,它将解除分配与破坏分开.这是有道理的,因为从中获取内存与在c ++中正确构造对象或多或少无关.
因此,有两个构造/释放函数对于默认实现看起来像这样(直接从书中解除):
void construct(pointer p, const T& val) { new(p) T(val); }
void destroy(pointer p) { p->~T(); }
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,构造只是调用placement new和destroy只是调用析构函数.
是否有任何理由使用这些而不仅仅使用placement new和析构函数语法?一个"正确的"分配器可以用另一种方式实现这些吗?或者我保证符合标准的所有分配器实现都会以这种方式实现构造/销毁方法吗?
更重要的是,可以说我可以随时使用std::uninitialized_copy
和std::uninitialized_fill
构建容器的元素吗?
谢谢.
我有一个在低延迟环境中运行的(java)应用程序,它通常处理大约600微米(+/- 100)的指令.当然,随着我们进一步进入微秒空间,您看到的成本延迟会发生变化,现在我们已经注意到2/3的时间用于分配2个核心域对象.
基准测试已将代码的违规部分与现有引用中的对象构造完全隔离,即基本上是一组引用(每个类中约15个)和一些新的列表,但请参阅下面关于确切测量的内容的注释这里.
每个人一直需要~100微米,这对我来说是莫名其妙的,我试图找出原因.一个快速的基准测试表明,一个类似大小的对象充满了字符串需要大约2-3微米到新的,显然这种基准充满了困难,但认为它可能是有用的基线.
这里有2个Q.
请注意,所涉及的硬件是Sun X4600上的Solaris 10 x86,带有8*双核opteron @ 3.2GHz
我们看过的东西包括
任何和所有的想法赞赏
for/while/do中的很多c/malloc()会消耗很多时间,所以我很好奇是否有任何操作系统为快速malloc缓冲内存.
我一直在思考是否可以通过为malloc编写一个"贪婪"的包装来加速malloc的速度.例如,当我要求1MB内存时,初始分配器将分配10MB,而在第二,第三,第四等...调用malloc函数将简单地从块中返回内存,首先分配"正常"方式.当然,如果没有足够的可用内存,你需要分配一个新的贪婪的内存块.
不知何故,我认为某人之前必须做过这件事或类似事情.所以我的问题很简单:这是否能够显着加快内存分配过程.(是的,我可以在提出问题之前尝试过,但如果没有必要,我只是懒得写这样的东西)
std::allocator
的construct
和destroy
成员函数上构造元素的类型参数化:
template<class T>
class allocator
{
public:
typedef T value_type;
typedef T* pointer;
template<class U, class... Args>
void construct(U *p, Args&&... args);
template<class U>
void destroy(U *p);
...
};
Run Code Online (Sandbox Code Playgroud)
这是什么理由?为什么他们不采取value_type*
或pointer
?似乎allocator<T>
应该只知道如何构造或销毁类型的对象T
.
什么时候应该而且不应该在python中预先分配列表?例如,我有一个带有2个列表的函数,并从中创建列表列表.很像,但不完全是矩阵乘法.我应该预先分配结果,
X = Len(M)
Y = Len(F)
B = [[None for y in range(Y)] for x in range(X)]
for x in range(X):
for y in range(Y):
B[x][y] = foo(M[x], F[y])
return B
Run Code Online (Sandbox Code Playgroud)
或者在我去的时候动态创建它?
B = []
for m in M:
B.append([])
for f in F:
B[-1].append(foo(m, f))
return B
Run Code Online (Sandbox Code Playgroud)
预分配似乎是不必要的,也许更慢,但动态地看起来是混淆的.特别是,B[-1].append(...)
似乎难以辨认.
我有构造一个函数std::string
从一个const char*
与两个数字,作为参数传递,追加到它的结束.
std::string makeName(const char* name, uint16_t num1, uint16_t num2) {
std::string new_name(name);
new_name.reserve(new_name.length()+5);
new_name += ":";
new_name += boost::lexical_cast<std::string>(num1);
new_name += ":";
new_name += boost::lexical_cast<std::string>(num2);
return new_name;
}
Run Code Online (Sandbox Code Playgroud)
该函数被调用数千次,以便为堆上分配的小对象创建唯一的名称.
Object* object1= new Object(makeName("Object", i, j)); // i and j are simply loop indices
Run Code Online (Sandbox Code Playgroud)
我发现使用valgrind的massif工具调用makeName会分配大量内存,因为它被调用了很多次.
87.96% (1,628,746,377B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->29.61% (548,226,178B) 0xAE383B7: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
| ->26.39% (488,635,166B) 0xAE38F79: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
| | …
Run Code Online (Sandbox Code Playgroud) 在他的演讲"效率与算法,性能与数据结构"中,Chandler Carruth谈到了在C++中需要更好的分配器模型.当前的分配器模型侵入了类型系统,因此很难在许多项目中工作.另一方面,Bloomberg分配器模型不会入侵类型系统,而是基于虚函数调用,这使得编译器无法"看到"分配并对其进行优化.在他的演讲中,他谈到编译器重复删除内存分配(1:06:47).
我花了一些时间来找到一些内存分配优化的例子,但我发现这个代码示例,在clang下编译,优化掉所有的内存分配,只返回1000000而不分配任何东西.
template<typename T>
T* create() { return new T(); }
int main() {
auto result = 0;
for (auto i = 0; i < 1000000; ++i) {
result += (create<int>() != nullptr);
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
以下论文http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html也说分配可以在编译器中融合,似乎表明一些编译器已经做了那种排序东西的.
由于我对高效内存分配的策略非常感兴趣,我真的很想理解为什么Chandler Carruth反对Bloomberg模型中的虚拟调用.上面的例子清楚地表明,clang可以在看到分配时优化.
在我的小型性能问题调查期间,我注意到一个有趣的堆栈分配功能,这里是测量时间的模板:
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int x; //for simple optimization suppression
void foo();
int main()
{
const size_t n = 10000000; //ten millions
auto start = high_resolution_clock::now();
for (size_t i = 0; i < n; i++)
{
foo();
}
auto finish = high_resolution_clock::now();
cout << duration_cast<milliseconds>(finish - start).count() << endl;
}
Run Code Online (Sandbox Code Playgroud)
现在全部是关于foo()
实现,在每个实现中将总共分配500000 ints
:
分配在一个块中:
void foo()
{
const int size = 500000;
int a1[size];
x = a1[size - …
Run Code Online (Sandbox Code Playgroud)allocation ×10
c++ ×5
c ×4
memory ×3
malloc ×2
stack ×2
allocator ×1
c++11 ×1
calloc ×1
java ×1
jvm-hotspot ×1
latency ×1
list ×1
low-level ×1
obfuscation ×1
optimization ×1
performance ×1
python ×1
standards ×1
stdstring ×1
valgrind ×1