关于在堆中申请内存的思考

本文通过示例程序分析了C/C++中使用`malloc()`、`new`在堆上申请内存的内部机制。揭示了内存分配并非仅仅为用户指定大小,额外还有用于边界标识和内存管理的字节。讨论了不同数据类型分配内存时额外字节数的变化,并提出了对于内存管理的猜想。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

//日期:2009.03.20

//作者:goodshell

//转载请注明来源:http://blog.youkuaiyun.com/goodshell

关于在堆中申请内存的思考

 

今天给同学演示关于在堆、栈中申请内存的区别,顺便解决了一下自己的问题,如下。

问题:C中的malloc()和free()、C++中的new和delete相信大家都很熟悉了,但这些函数和操作符究竟为我们做了什么呢?分配的内存真的等于我们想要的大小吗?

看下面的程序段:

 

现在看一下输出(实际是就是我们刚才申请的内存区),或许我们能从中看出点什么:

-----------------------

6 7 8 9

-3 -3 -3 -3

0 0 0 0

0 0 0 0

7 0 7 0

35 1 8 0

64 33 55 0

-80 33 55 0

0 0 0 0

0 0 0 0

4 0 0 0

1 0 0 0

45 0 0 0

-3 -3 -3 -3

1 2 3 4

-3 -3 -3 -3

0 0 0 0

-----------------------

在上面的程序中我们申请了两块内存,都是4个字节,从上面的内存中我们就很容易分辨出来,6789和1234两块内存。对于我们申请 p2= new char [4]这部分内存,实际上申请的并不只是4个字节,除了我们要求的1234这4个字节,另外还分配了13*4=52个字节的内存。在我们真正需要的数据的前后,都有4个字节的-3,我推断这个很可能是分界符吧,用来标识我们所申请内存的起始和结束位置。 从我们想要的内存数据开始向上数16个字节值是“4”,这个正是我们分配的内存区的大小。当改变申请的内存区的大小时,这个值也要相应地发生改变,验证了刚才的推断。

以前我们可能就有这样的疑问,为什么要释放内存时只把指针传给delete或free()就可以了,或许我们能从这多出来的内存区里找到答案。我现在猜想应该是这个额外分配的内存的缘故,当然,现在只是猜想而已。

但真的是一定多分配52个字节吗,似乎不是这样,现在我们把上面的程序改一下

 

这时内存的内容如下,

-----------------------

6 0 0 0

7 0 0 0

8 0 0 0

9 0 0 0

-3 -3 -3 -3

0 0 0 0

0 0 0 0

0 0 0 0

9 0 9 0

86 1 8 0

64 33 55 0

-48 33 55 0

0 0 0 0

0 0 0 0

16 0 0 0

1 0 0 0

45 0 0 0

-3 -3 -3 -3

1 0 0 0

2 0 0 0

3 0 0 0

4 0 0 0

-3 -3 -3 -3

-----------------------

可以看到,这时多分配的内存大小是14*4=56个字节,为何要这样,我现在也没有搞明白,但或许我们能从《操作系统》这本书里找到答案。但是,我们上面总结的规律在这里似乎还是有效的,即4个-3作为分界符,申请的内存大小是从我们想要的内存数据开始向上数16个字节的值来标识的(或许不只这一个字节,而是从这个字节开始的连续4个字节做为一个int型数据来决定的)。

以上仅是拙见而已,还请大家多多指正。

 

<think>嗯,用户在使用Ubuntu进行编译时遇到了内存不足的问题,需要释放更多内存或优化内存使用。首先,我得回忆一下相关的知识,并结合之前提供的引用内容来思考解决方案。 首先,根据引用[1]提到的,当申请超过128K的内存时,系统会使用mmap来分配内存,这可能涉及到和栈之间的空闲区域。如果编译过程中需要大量内存,可能会频繁调用mmap,这时候系统内存不足的话,可能需要优化编译器的内存使用或者增加可用内存。 然后,用户的问题是关于Ubuntu编译时的内存不足。可能的原因包括物理内存不足、交换空间不足,或者编译设置不当导致内存使用过高。需要从这几个方面入手。 首先想到的是增加交换空间。因为交换空间可以作为虚拟内存,当物理内存不足时,系统会把部分内存数据转移到交换分区。用户可能没有足够的交换空间,或者现有的交换空间太小。这时候,可以建议用户创建一个交换文件,临时扩展交换空间。比如使用fallocate或者dd命令创建一个大文件,然后设置为交换空间,并启用它。这样就能临时增加可用内存了。 另外,调整交换空间的swappiness参数也可能有帮助。这个参数控制系统使用交换空间的倾向,默认是60,适当降低可能让系统更倾向于保留物理内存,但需要根据具体情况调整。不过,如果编译需要大量内存,可能调高反而有助于防止OOM killer终止进程,需要进一步验证。 接下来是优化编译器的并行进程数。比如,使用make时,如果同时运行的线程太多,每个线程都需要占用内存,可能导致总和超过可用内存。减少并行数,比如将make -j4改为make -j2,可以减少内存使用峰值。这时候需要权衡编译速度和内存使用,找到一个合适的平衡点。 然后,关闭后台程序也是一个直接的方法。用户在编译时可能运行了其他占用内存的应用,比如浏览器、IDE等,关闭这些可以释放物理内存使用top或htop命令查看内存占用情况,结束不必要的进程。 还有使用内存更小的编译工具链。比如,某些编译器可能在内存使用上更高效,或者选择轻量级的工具。比如,使用Clang而不是GCC,或者某些优化过的编译工具,可能减少内存消耗。但需要确认项目是否支持这些替代工具。 另外,增加物理内存使用zram。如果用户的主机允许,升级RAM是最直接的解决方案。但如果是虚拟机或云实例,可能需要调整配置。而zram是Linux内核模块,用压缩内存作为交换空间,效率更高,适合内存不足的情况。启用zram可能不需要额外硬件,但需要配置。 还有调整编译选项。比如,优化编译器的参数,减少调试信息(-g0)、优化级别(比如-O1比-O3可能更少内存),或者分阶段编译,将项目分成多个部分编译,减少单次内存需求。例如,分模块编译,每次只编译一部分代码。 另外,使用ccache来缓存编译结果,虽然主要作用是加速编译,但重复编译时减少重新编译的次数,间接减少内存使用。特别是当多次编译相似代码时,缓存命中率高的话,可以避免重复处理,节省内存。 然后,检查是否有内存泄漏。虽然编译过程一般是短暂的,但某些情况下,编译器或脚本可能有内存泄漏,导致内存耗尽。使用valgrind等工具监测内存使用,不过这可能比较复杂,适合进阶用户。 最后,使用分布式编译工具,比如distcc,将编译任务分发到多台机器,减少单机的内存压力。不过这需要额外的设置和网络环境,可能对普通用户来说门槛较高。 需要结合用户的实际场景,如果是物理内存确实不足,增加交换空间和关闭后台程序是最快捷的方法。如果是编译大型项目,调整并行数和编译选项更有效。同时,引用[2]提到Ubuntu版本和CUDA的关系,如果用户是在进行CUDA相关的编译,可能需要确保驱动和工具链的正确安装,但这里问题核心是内存,所以可能不需要涉及驱动部分。引用[3]关于磁盘分区的建议,可能和交换文件创建有关,因为交换文件需要磁盘空间,所以确保有足够的空间在对应分区,比如/home或根目录下。 总结下来,步骤可能包括: 1. 检查内存和交换空间使用情况(free -h)。 2. 增加交换文件。 3. 调整编译并行数。 4. 关闭不必要的程序。 5. 使用内存优化选项或工具。 6. 考虑硬件升级或zram。 需要将这些步骤以清晰的方式呈现给用户,并给出具体的命令示例,比如创建交换文件的步骤,调整make的-j参数等。同时,提醒用户注意操作的风险,比如修改swappiness或使用sudo命令需要权限。</think>### 解决Ubuntu编译时内存不足的方法 #### 1. **增加交换空间(Swap)** - **创建临时交换文件**(推荐): ```bash sudo fallocate -l 4G /swapfile # 创建4GB文件,根据需求调整大小 sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile ``` 完成后可通过 `free -h` 验证交换空间是否生效。此方法通过分配磁盘空间作为虚拟内存,缓解物理内存不足的问题[^1]。 - **永久生效**:将 `/swapfile swap swap defaults 0 0` 添加到 `/etc/fstab`。 #### 2. **优化编译参数** - **减少并行编译进程数**: 编译工具如 `make` 默认使用高并行度(如 `make -j$(nproc)`),这会占用大量内存。改为更小的并行数,例如: ```bash make -j2 # 根据实际内存调整数值 ``` - **使用轻量级编译选项**: 在编译命令中添加 `-O1`(优化级别较低,减少内存占用)或关闭调试符号 `-g0`: ```bash CFLAGS="-O1 -g0" ./configure ``` #### 3. **释放现有内存** - **清理缓存**: 释放系统缓存(不影响运行中的程序): ```bash sudo sync && echo 3 | sudo tee /proc/sys/vm/drop_caches ``` - **关闭非必要程序**: 通过 `htop` 或 `top` 查找占用内存的进程并终止。 #### 4. **使用内存优化工具** - **启用ZRAM**: ZRAM通过压缩内存数据提升利用率,适合内存紧张的场景: ```bash sudo apt install zram-config sudo systemctl restart zram-config ``` #### 5. **检查磁盘分区与存储** - 确保根目录或 `/home` 有足够空间分配交换文件。若磁盘空间不足,需清理文件或调整分区[^3]。 #### 6. **升级硬件或使用云资源** - 长期频繁遇到内存不足时,建议升级物理内存。 - 如果是虚拟机或云服务器,可临时扩容配置。 --- ### 相关问题 1. 如何监控Ubuntu系统的实时内存使用情况? 2. 交换空间(Swap)与ZRAM的工作原理有什么区别? 3. 编译Linux内核时如何避免内存不足问题? --- 通过上述方法,可有效缓解编译过程中的内存压力。若涉及CUDA等特殊环境,需确保驱动版本与系统兼容(如CUDA 11+支持Ubuntu 20.04)[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值