malloc的默认行为

大家都知道C++中可以直接调用malloc请求内存被返回分配成功的内存指针,该指针指向的地址就是分配得到的内存的起始地址。比如下面的代码

int main()
{
void *p = malloc(1024);
printf("0x%p\n", p);
free(p);
}

请求了一个大小为1024的内存块并打印出来,一切都很完美。

我们看看这块内存的地址。

可以看到,在64bit机器上,malloc默认行为会将分配的地址以16-byte对齐,如果我们想改变这种默认行为,提供32-byte或者64-byte对齐,应该怎么做呢?

实现aligned_malloc

源代码

从C++17开始,可以使用aligned_alloc函数达到这个目的,但是如果使用较老的C++版本,如C++14,C++11,我们需要手动写一个实现。

话不多说,先贴代码如下,aligned_malloc和aligned_free,需要配合使用,否则会有内存泄漏问题。

#include <memory>

void* aligned_malloc(size_t size, size_t alignment)
{
size_t offset = alignment - 1 + sizeof(void*);
void * originalP = malloc(size + offset);
size_t originalLocation = reinterpret_cast<size_t>(originalP);
size_t realLocation = (originalLocation + offset) & ~(alignment - 1);
void * realP = reinterpret_cast<void*>(realLocation);
size_t originalPStorage = realLocation - sizeof(void*);
*reinterpret_cast<void**>(originalPStorage) = originalP;
return realP;
} void aligned_free(void* p)
{
size_t originalPStorage = reinterpret_cast<size_t>(p) - sizeof(void*);
free(*reinterpret_cast<void**>(originalPStorage));
} int main()
{
void * p = aligned_malloc(1024, 64);
printf("0x%p\n", p);
aligned_free(p);
return 0;
}

添加一个测试程序,

#include <assert.h>

void TestAlignedMalloc()
{
const int size = 100;
const int alignment = 64;
void* testArray[size];
for (int i = 0; i < size; ++i)
{
void * p = aligned_malloc(1024, alignment);
assert((reinterpret_cast<size_t>(p) & (alignment - 1)) == 0);
printf("0x%p\n", p);
testArray[i] = p;
}
for (int i = 0; i < size; ++i)
{
aligned_free(testArray[i]);
}
} int main()
{
TestAlignedMalloc();
return 0;
}

看看结果,

分配的内存地址都是以64-byte为边界,并且分配的内存最后也被成功释放了,函数是正确的。

源代码说明

本小段主要向不大了解解决思路的小伙伴做一些简单解释,程序大佬可以一笑而过哈。

首先我们要明确我们的解决方案,既然malloc分配的指针地址不能达到我们想要的字节对齐效果,我们就自己来调整这个指针。所以我们的做法是

  • 比用户实际需要的多分配一些内存,多分配的部分等于对齐大小减一再加上指针大小。加上对齐大小减一很好理解,是为了之后的对齐做准备,而加上指针大小是为了之后有空间保存原始指针,对应分配函数中的前2行
  • 在malloc返回的原始指针的基础上,加上指针大小,再对齐(采用的方法就是加上对齐大小减1再做位运算),这个运算结果就是我们想要的对齐后的指针,也是我们返回给用户的指针,对应分配函数中的3~5行
  • 我们还需要保存malloc返回的原始指针,否则free的时候会出问题。这时我们之前多分配的一个指针大小就有用武之地了,保存原始指针在那个地址,分配函数的最后几行就在做这个事
  • 当free的时候,我们知道原始指针存放在我们使用的指针的前一个指针大小偏移的内存里面,通过一些运算取得这个内存地址,再根据里面存放的原始指针调用free完成内存释放

这就是在C++中手动实现aligned_malloc的方法,希望大家在使用较老版本的C++的时候,有需要可以用上。如果使用的版本是C++17以上,那么还是推荐使用系统自带的方法。

在C++中实现aligned_malloc的更多相关文章

  1. Python开源框架

    info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...

  2. mapreduce中一个map多个输入路径

    package duogemap; import java.io.IOException; import java.util.ArrayList; import java.util.List; imp ...

  3. Hadoop 中利用 mapreduce 读写 mysql 数据

    Hadoop 中利用 mapreduce 读写 mysql 数据   有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...

  4. Python中的多进程与多线程(一)

    一.背景 最近在Azkaban的测试工作中,需要在测试环境下模拟线上的调度场景进行稳定性测试.故而重操python旧业,通过python编写脚本来构造类似线上的调度场景.在脚本编写过程中,碰到这样一个 ...

  5. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  6. Angular杂谈系列1-如何在Angular2中使用jQuery及其插件

    jQuery,让我们对dom的操作更加便捷.由于其易用性和可扩展性,jQuer也迅速风靡全球,各种插件也是目不暇接. 我相信很多人并不能直接远离jQuery去做前端,因为它太好用了,我们以前做的东西大 ...

  7. 关于CryptoJS中md5加密以及aes加密的随笔

    最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学 ...

  8. In-Memory:在内存中创建临时表和表变量

    在Disk-Base数据库中,由于临时表和表变量的数据存储在tempdb中,如果系统频繁地创建和更新临时表和表变量,大量的IO操作集中在tempdb中,tempdb很可能成为系统性能的瓶颈.在SQL ...

  9. SQL Server中的高可用性(2)----文件与文件组

        在谈到SQL Server的高可用性之前,我们首先要谈一谈单实例的高可用性.在单实例的高可用性中,不可忽略的就是文件和文件组的高可用性.SQL Server允许在某些文件损坏或离线的情况下,允 ...

随机推荐

  1. C# 静态类 单例模式 对比

    公司的类都需要使用单例模式实现,这个可以节省资源,避免重复对象的生成.但是静态类也可以做到这一点,而且写起来更简洁,于是查阅相关资料,希望弄明白两者的差别. 1.单例模式可以在用到的时候初始化,而静态 ...

  2. CentOS 7 升级内核版本

    1.查看当前内核版本 $ uname -r 3.10.0-514.el7.x86_64 $ uname -a Linux k8s-master 3.10.0-514.el7.x86_64 #1 SMP ...

  3. servlet相关知识点

    一.servlet的生命周期 Servlet(Sever Applet),全称是Java Servlet,是用java编写的服务器程序.Servlet是指任何实现了这个Servlet接口的类. ser ...

  4. spring再学习之简单测试

    一.spring是怎么工作的那,通过一个类装载进容器进行描述: 首先创建一个类user: package cn.itcast.bean; public class User { public User ...

  5. html图片占位符插件holder.js

    1.下载源码 下载链接:http://www.bootcdn.cn/holder/ 2.在HTML中引入holde.js <script src="holder-js-2.9.4\ho ...

  6. Netty(五)Netty 高性能之道

    4.背景介绍 4.1.1 Netty 惊人的性能数据 通过使用 Netty(NIO 框架)相比于传统基于 Java 序列化+BIO(同步阻塞 IO)的通信框架,性能提升了 8 倍多.事 实上,我对这个 ...

  7. Linux下/bin和/sbin的区别

    bin: bin为binary的简写主要放置一些系统的必备执行档例如:cat.cp.chmod df.dmesg.gzip.kill.ls.mkdir.more.mount.rm.su.tar等./u ...

  8. Bootstrap导航组件

    Bootstrap 中的导航组件都依赖同一个 .nav 类,状态类也是共用的.改变修饰类可以改变样式. 标签页 注意 .nav-tabs 类依赖 .nav 基类 <ul class=" ...

  9. git merge bug

    git merge bug 本地分支 dev commit 后, 直接 pull 远程 dev 分支, 导致远程 dev 分支 merge 到本地 dev 分支了, 取消本次 merge 操作? Re ...

  10. svg click event bug & css pointer-events

    svg click event bug & css pointer-events svg click event not working Error OK ??? css class /* d ...