根据C++标准(继承自C),空结构仍然具有非零大小.这个(可怜的恕我直言)的原因是两个不同的变量应该有不同的地址.现在,继承一个空结构并不总是"膨胀"该对象.但在某些情况下情况就是这样.
我有一个相当复杂的类架构,涉及激烈的模板巫术.结果,最后的类(我需要创建的实例)可能有几个继承的空结构.由于这个事实,他们中的一部分最终可能会被夸大.最糟糕的是,他们的内存布局实际上取决于继承的顺序.
如果有可能的话,我想摆脱这一切.
是否有一个C++编译器可以配置为消除这种空间浪费,实际上是打破标准的代价?
编辑:
我是说这个:
struct Empty1 {};
struct Empty2 {};
struct NonEmpty {
int Value;
};
struct MyClass1
:public NonEmpty
,public Empty1
,public Empty2
{
};
struct MyClass2
:public Empty1
,public NonEmpty
,public Empty2
{
};
struct MyClass3
:public Empty1
,public Empty2
,public NonEmpty
{
};
STATIC_ASSERT(sizeof(MyClass1) == 8);
STATIC_ASSERT(sizeof(MyClass2) == 4);
STATIC_ASSERT(sizeof(MyClass3) == 8);
Run Code Online (Sandbox Code Playgroud)
不仅空结构会使对象膨胀(当多个这样的东西继承时),而且结果还取决于空结构的继承顺序.
我在我的一个项目中使用自定义堆实现.它由两个主要部分组成:
修复了大小块堆.即只分配特定大小的块的堆.它分配更大的内存块(虚拟内存页或来自另一个堆),然后将它们分成原子分配单元.
它快速执行分配/释放(在O(1)中)并且没有内存使用开销,没有考虑外部堆强加的事情.
全球通用堆.它由上面(固定尺寸)堆的桶组成.WRT它选择适当存储桶的请求分配大小,并通过它执行分配.
由于整个应用程序(大量)是多线程的 - 全局堆在其操作期间锁定适当的存储桶.
注意:与传统堆相比,此堆不仅要求分配大小,还要求释放分配大小.这允许在没有搜索或额外的内存开销的情况下识别适当的桶(例如在分配的块之前保存块大小).虽然不太方便,但在我的情况下这是好的.此外,由于"桶配置"在编译时是已知的(通过C++模板voodoo实现) - 在编译时确定适当的桶.
到目前为止,一切看起来(并且有效).
最近我研究了一种能够大量执行堆操作的算法,并且自然会受到堆性能的影响.分析显示其锁定会对其性能产生很大影响.也就是说,堆本身工作得非常快(典型的分配只涉及一些内存解除引用指令),但由于整个应用程序是多线程的 - 适当的存储桶受关键部分的保护,它依赖于互锁指令,这些指令很多重.
我通过给这个算法提供了自己的专用堆来解决这个问题,这个堆不受关键部分的保护.但这在代码级别强加了几个问题/限制.例如,需要在堆栈深处传递上下文信息,无论堆可能在哪里.也可以使用TLS来避免这种情况,但这可能会导致我在特定情况下重新进入时出现一些问题.
这让我想知道:是否有一种已知的技术来优化堆(但不限于)单线程使用?
编辑:
特别感谢@Voo建议查看google的tcmalloc.
它似乎与我做的更多或更少(至少对于小对象)的工作类似.但此外,他们通过维护每线程缓存来解决我所遇到的确切问题.
我也想过这个方向,但我想保持每线程堆.然后释放从属于另一个线程的堆分配的内存块有点棘手:应该将其插入到一个锁定队列中,并且应该通知其他线程,并异步释放挂起的分配.异步释放可能会导致问题:如果该线程由于某种原因而忙(例如执行积极的计算) - 实际上不会发生内存释放.此外,在多线程场景中,释放的成本要高得多.
OTOH使用缓存的想法似乎更简单,更有效.我会尝试解决它.
非常感谢.
PS:
事实上谷歌的tcmalloc很棒.我相信它的实现与我所做的非常相似(至少是固定大小的部分).
但是,要迂腐,有一件事我的堆优越.根据文档,tcmalloc大约1%的开销(渐近),而我的开销是0.0061%.确切地说是4/64K.
:)
我的一个朋友告诉我,在x86架构上,DMA控制器无法在两个不同的RAM位置之间进行传输.它只能在RAM和外设之间传输(如PCI总线).
这是真的?
因为AFAIK DMA控制器应该能够位于BUS上并具有地址的任意设备之间.特别是如果源和destionation地址属于同一物理设备,我认为没有问题.
我需要一个(最好是简单快速)的图像散列算法.散列值用于查找表,而不用于加密.
一些图像是"计算机图形" - 即纯色填充的光栅,光栅化文本等,而还有"摄影"图像 - 包含丰富的色谱,大多是光滑的,具有合理的噪声幅度.
我也希望哈希算法能够应用于特定的图像部分.我的意思是,图像可以分为网格单元格,每个单元格的哈希函数应该仅取决于该单元格的内容.因此,如果两个图像具有共同区域(如果它们被适当地对齐),则可以快速发现.
注意:我只需要知道两个图像(或它们的部分)是否相同.也就是说,我不需要匹配类似的图像,不需要特征识别,相关和其他DSP技术.
我想知道什么是首选的散列算法.
对于"摄影"图像,只需对网格单元格内的所有像素进行异或运算即可.不同图像的相同散列值的概率非常低,特别是因为(几乎白色)噪声的存在打破了所有潜在的对称性.此外,这种散列函数的频谱看起来很好(任何值都可能以几乎相同的概率).
但是这种天真的算法可能不会与"人工"图形一起使用.对于这样的图像,相同的像素,重复图案,几何偏移不变性是非常常见的.对于具有偶数个相同像素的任何图像,对所有像素进行异或将给出0.
使用像CRT-32这样的东西看起来很有希望,但我想更快地找出一些东西.我想到了迭代公式,每个新像素都会改变当前的哈希值,如下所示:
hashValue = (hashValue * /*something*/ | newPixelValue) % /* huge prime */
Run Code Online (Sandbox Code Playgroud)
做模数素数应该可以很好地分散,所以我倾向于这个选项.但我想知道是否有更好的变种.
提前致谢.
我正在研究一种需要通过UDP(一种视频通话)实时传输H.264编码视频的应用程序.
最近我们改用硬件编码器,它只支持有限数量的H.264配置文件.结果,每个编码视频帧现在由单个NALu组成.更确切地说,对于IDR(关键)帧,编码器为其他帧生成SSP,PSP和单个IDR切片 - 单个非IDR切片.
现在,我的目标是将切片NALu分成几个较小的切片,因为如果NALu无法完全组装,则会丢失数据包 - 它完全丢失了.至少我需要在空间上分割切片,即将宏块的范围放入不同的NALus中.如果可能的话 - 我还想提取高质量的图层,以便可以通过更多冗余数据包(FEC)保护基础层.
注意:我不是在谈论转码.它是关于重新打包/重新格式化,定位宏块定义数据块并以不同的方式放置它们.
我现在正在尝试使用H.264标准规范和一些开源解码器代码来解析相应的数据头:SPS,PPS和编码片.这项任务似乎有可能,虽然有点棘手,但有很多技术细节.
我的问题是:这是一个已知的问题吗?是否有一些API /库正是这样做的?
Windows中的内核模式驱动程序是否存在线程局部存储(TLS)等效(确切地说是Win32)?
我试图实现的目标:
最终,在我的驱动程序的调度程序中,它可能会调用许多其他函数(可能存在深度调用).我想提供一些特定于正在处理的请求的上下文信息.也就是说,我有一些结构,指针应该在所有被调用的函数中都可见,而不是将它作为参数显式传递给每个函数.
使用static/global不是一个完美的选择(多线程,同步对象等).
如果那是用户模式代码 - 在这种情况下显然会使用TLS.但是AFAIK没有像TlsGetValue/ 这样的内核模式功能TlsSetValue.这是有道理的 - 要使这些功能工作,必须首先分配一个进程范围的TLS索引.OTOH驱动程序代码可以在任意线程上调用,不限于特定进程.
但是,我实际上并不需要持久的特定于线程的存储.我只需要一个特定于线程的存储来进行顶级函数调用.
我想我知道如何以一种黑客的方式"实施"TLS.我将始终使用预定义的索引(例如,index = 0),而不是分配TLS索引.在顶级函数中,我将保存存储的TLS值,并用所需的值覆盖它.完成后,将恢复保存的值.
幸运的是我知道如何在Win32中实现TLS.TIB每个线程都有一个结构(线程信息块).在每个线程中,可以使用FS:[18h]选择器访问它.在TIB包含(除其他外)通过TLS使用的阵列.其余的非常简单.
但是,我更愿意使用官方API来实现类似的功能.
提前致谢.
PS One理论上可以使用SEH(也存储每线程信息).也就是说,包装顶级代码__try/__except,然后在需要上下文信息的地方 - 用一些参数引发可持续异常,在__except块中用上下文信息填充参数,然后恢复执行.这是一个100%有效的程序流程,不使用未记录的功能.但对我来说这似乎是一个丑陋的黑客,更不用说性能并发症了.
我的项目中有一个源文件,它有超过65,536个代码行(确切地说是112,444).我正在使用"sqlite amalgamation",它出现在一个巨大的源文件中.
我正在使用MSVC 2005.问题在调试期间到来.一切都编译和链接确定.但是当我尝试使用调试器进入函数时 - 它显示的代码行不正确.
有趣的是,正确的行号和调试器显示的行号之间的差异正好是65536.这让我怀疑(几乎可以肯定)一些无符号的短溢出.
我也怀疑它不是MSVC本身的错误.也许这是调试信息格式的限制.也就是说,MSVC使用的调试信息格式将行号存储为2字节短路.
有没有什么可以做的(除了将大文件切成几个较小的文件)?
我正在使用WinDbg调试Windows的内核模式设备驱动程序.是否有可能按需创建一个小型转储?
我的意思是,我的一个断点被击中,系统停止了.我想创建一个minidump(让我们说只有堆栈).这有WinDbg关键字吗?
提前致谢
以下代码由clang编译到wasm平台:
uint64_t Get() const
{
uint32_t ord = -m_Order;
if (ord >= 64)
return 0;
return m_Num >> ord;
}
Run Code Online (Sandbox Code Playgroud)
编译后的 wasm 代码(启用优化)如下所示:
i64.const 0
local.get $l4
i32.const 0
local.get $p2
i32.sub
local.tee $l5
i64.extend_i32_u
i64.shr_u
local.get $l5
i32.const 63
i32.gt_u
select
Run Code Online (Sandbox Code Playgroud)
正如我们所看到的,表达式m_Num >> ord总是被求值,但最终结果将是 it 或0(第一个命令将其放在操作数堆栈上)。
我们在虚拟机上运行生成的 wasm 代码。问题是:当-m_Order大于63时,程序崩溃(即陷入困境,虚拟机不会崩溃),因为移位操作比操作数大小更多的位被认为是未定义的行为。
根据 LLVM 文档,这不是未定义的行为,它只是未定义的结果(所谓的毒害值)。
所以,我的问题是:是否有可能阻止 LLVM 进行这种优化?即不允许优化器产生未定义的结果,这些结果不应该由原始代码产生?
更新:
澄清:正如我们所发现的,WebAssembly 标准明确允许这样做。对于移位运算符,移位计数可以大于最大位数,在这种情况下,移位计数必须以最大位数为模进行处理(类似于 x86 处理器处理此问题的方式)。所以它甚至不是未定义的结果。
所以这是我们虚拟机的问题,它与标准有偏差。解决这个问题不是问题,但升级整个系统就有问题,所以我们更愿意保留当前的行为。我们需要一种解决该问题的方法。
我发现的一种解决方案是在块内调用一些第三方虚拟函数if,这将强制编译器生成正确的分支,而不是计算所有变体并通过select. 我的意思是:
uint64_t Get() const
{ …Run Code Online (Sandbox Code Playgroud) 我想我会疯了.
我有一段代码需要创建一个(无符号)整数,其N后续位设置为1.确切地说,我有一个位掩码,在某些情况下,我想将它设置为一个实心的rnage.
我有以下功能:
void MaskAddRange(UINT& mask, UINT first, UINT count)
{
mask |= ((1 << count) - 1) << first;
}
Run Code Online (Sandbox Code Playgroud)
简单来说:1 << count在二进制表示中100...000(零的数量是count),从这样的数字中减去1给出011...111,然后我们只是左移它first.
当满足以下明显限制时,上述结果应产生正确的结果:
first + count <= sizeof(UINT)*8 = 32
请注意,它也应该适用于"极端"情况.
count = 0我们有(1 << count) = 1,因此((1 << count) - 1) = 0.count = 32我们有(1 << count) = 0,因为前导位溢出,并且根据C/C++规则,按位移位运算符不是循环的.然后 …