Linux性能学习(2.2):内存_进程线程内存分配机制探究

news2024/11/18 9:33:50

文章目录

  • 1 进程内存分配探究
    • 1.1 代码
    • 1.2 试验过程
  • 2 线程内存分配探究
    • 2.1 代码
    • 2.2 试验过程
  • 3 总结

参考资料:
1. 嵌入式软件开发杂谈(3):Linux下内存与虚拟内存
2. 嵌入式软件开发杂谈(1):Linux下最大能创建多少线程?

在链接1中,我们可以了解到系统为每一个进程分配了4GB的虚拟内存空间,其中3GB为用户空间,是每个进程独有的,1GB为内核空间,所有的进程以及内核共同享有。

在链接2中,我们了解到系统为每个线程分配独立的堆栈,不同的系统有不同的大小,在32位linux系统上默认为8MB。

在上篇文章中介绍了系统以及进程相关的内存指标,但是有个疑问,当进程运行时候,系统是如何来分配内存的,是直接分配3GB给到内存,还是按需分配,最大3GB,通过下面代码来探究一番。

PS:下面测试环境为Ubuntu 64位系统。

1 进程内存分配探究

1.1 代码

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int ch = 0;
	int s32Size = 1024;
	char* s8Ptr = NULL;
	int s32Cnt = 0;
	
	while ((ch = getchar()) != EOF)
	{
		printf("get char,malloc %d mem\n", s32Size);
		s8Ptr = NULL;
		s8Ptr = (char*)malloc(s32Size);
		if (NULL == s8Ptr)
		{
			printf("malloc err\n");
		}
		else
		{
			printf("malloc success, cnt:%d, addr:%p\n", ++s32Cnt, s8Ptr);
		}
	}
	
	return 0;
}

上面代码,每当我们在终端输入一个字符,程序就申请1KB的内存,并且打印申请内存的地址。

1.2 试验过程

我们知道,堆是负责动态内存的分配,因此可以通过 # cat /proc/$(pid)/maps | grep heap
来查看进程的内存分配情况。

运行程序,然后使用top查看虚拟内存的使用情况以及使用上面指令来查看堆的使用情况。
在这里插入图片描述

# cat /proc/11031/maps | grep heap
00ae2000-00b03000 rw-p 00000000 00:00 0 

从上面可以可以看到这个进程的虚拟内存使用量为4352KiB,堆的地址为00ae2000-00b03000,换算一下堆的大小为132KB。但是此时程序并没有申请内存,怎么回事?

我们第一次申请内存,打印如下:

get char,malloc 1024 mem
malloc success, cnt:1, addr:0xae2830

然后查看虚拟内存VIRT使用量,还是4352KiB,并没有增加,堆的使用地址还是00ae2000-00b03000,也没有改变。

继续申请内存:

get char,malloc 1024 mem
malloc success, cnt:2, addr:0xae2c40
get char,malloc 1024 mem
malloc success, cnt:3, addr:0xae3050

第二次和第三次申请内存,VIRT和堆的信息仍然维持原状,没有改变,继续申请:

get char,malloc 1024 mem
malloc success, cnt:128, addr:0xb02c20

直到第128次申请内存时候,VIRT的使用量为4484KiB,比4352增加了132KB,而堆的使用量为264KB,比上次增加了132KB,信息如下:
在这里插入图片描述

cat /proc/11031/maps | grep heap
00ae2000-00b24000 rw-p 00000000 00:00 0                                  [heap]

继续申请内存,直到第258次申请内存,VIRT变为4616K,比4484增加了132KB,而堆的使用量为396KB,比上次增加了132KB,信息如下:

get char,malloc 1024 mem
malloc success, cnt:258, addr:0xb23c40

在这里插入图片描述



# cat /proc/11031/maps | grep heap
00ae2000-00b45000 rw-p 00000000 00:00 0                                  [heap]

从上面的测试中,我们看到第二次申请内存的地址为0xae2c40,而第一次申请内存的地址为0xae2830,两者相减,为1040,但是我们只申请了1024个字节,为什么会多16个字节?
第一个问题:为什么系统分配的内存比实际申请的内存大16个字节?

然后,我们可以看到,当程序运行时候,系统已经先为程序分配了132KB的内存,在随后我们申请内存时候,一直使用的是系统预先申请的132KB内存,直到我们申请的内存超过132KB,然后系统再次申请132KB,而不是我们需要多少就申请多少?
第二个问题:为什么系统会给进程申请132KB的内存,而不是我们真正需要的内存?

2 线程内存分配探究

2.1 代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/prctl.h>

void *fun(void *arg)
{
	printf("----->thread_test\n");
	prctl(PR_SET_NAME, "thread_test");
	int ch = 0;
	int s32Size = 1024;
	char* s8Ptr = NULL;
	int s32Cnt = 0;
	
	while ((ch = getchar()) != EOF)
	{
		printf("get char,malloc %d mem\n", s32Size);
		s8Ptr = NULL;
		s8Ptr = (char*)malloc(s32Size);
		if (NULL == s8Ptr)
		{
			printf("malloc err\n");
		}
		else
		{
			printf("malloc success, cnt:%d, addr:%p\n", ++s32Cnt, s8Ptr);
		}
	}
}

int main()
{
	int s32Ret = 0;
	pthread_t thread;
	
	if (getchar() != EOF)
	{
		s32Ret = pthread_create(&thread, NULL, fun, NULL);		
		printf("pthread_create, ret:%d\n", s32Ret);
	}
	
	while(1) sleep(10);
	return 0;
}

上面代码,当我们第一次输入一个字符,则创建线程,随后再次输入字符则是分配内存

2.2 试验过程

运行程序,查看VIRT为6520KB,如下:
在这里插入图片描述

maps信息如下:
在这里插入图片描述

然后我们创建线程,查看VIRT和maps信息如下:
在这里插入图片描述
在这里插入图片描述

可以看到,VIRT由6520增加到14716,即增加了8MB,这个8MB是系统为每个线程创建时分配的。
然后开始第一次分配内存,VIRT和maps信息如下:
在这里插入图片描述
在这里插入图片描述

可以看到,当我们第一次申请内存的时候,VIRT由14716增加到80252,即系统为线程申请了64MB内存,而不是给进程分配的132KB内存。
第三个问题:为什么系统会给线程申请64MB的内存,而不是我们真正需要的内存?

开始第二次申请内存,VIRT和maps数据均没有变化,和进程中的分配机制一样,先从已经分配的内存中使用,当超过已经分配的内存时,才会重新分配新的内存。

get char,malloc 1024 mem
malloc success, cnt:1, addr:0x7f9bac0008c0

get char,malloc 1024 mem
malloc success, cnt:2, addr:0x7f9bac000cd0

上面是程序的打印信息,可以看到我们申请了1024字节的内存,但是系统还是分配了1040个字节的内存,即多分配了16字节的内存,和问题1一致。

3 总结

通过上面的测试,我们得出了三个问题:

  • 第一个问题:64位系统,为什么系统分配的内存比实际申请的内存大16个字节?
  • 第二个问题:64位系统,为什么系统会给进程申请132KB的内存,而不是我们真正需要的内存?
  • 第三个问题:64位系统,为什么系统会给线程申请64MB的内存,而不是我们真正需要的内存?

后面章节将解决这几个问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/388949.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cookie+Session详解

文章目录批量删除会话技术简介CookieCookie 查看Cookie 的删除Cookie 使用页面获取 cookie 信息cookie 特点Sessionsession 的使用Session 登录权限验证过滤器简介过滤器的使用WebFilter 注解过滤放行登录权限验证批量删除 servlet 类 dao 层 会话技术 简介 在计算机领域…

论文阅读_近端策略优化_PPO

论文信息 name_en: Proximal Policy Optimization Algorithms name_ch: 近端策略优化算法 paper_addr: http://arxiv.org/abs/1707.06347 date_publish: 2017-08-28 if: IF 8.665 Q1 B1 Top EI author: John Schulman citation: 9685 读后感 PPO近端策略优化是一种强化学习算…

Linux 练习四 (目录操作 + 文件操作)

文章目录1 基于文件指针的文件操作1.1 文件的创建&#xff0c;打开和关闭1.2 文件读写操作2 基于文件描述符的文件操作2.1 打开、创建和关闭文件2.2 文件读写2.3 改变文件大小2.4 文件映射2.5 文件定位2.6 获取文件信息2.7 复制文件描述符2.8 文件描述符和文件指针2.9 标准输入…

Git标签与版本发布

1. 什么是git标签 标签&#xff0c;就类似我们阅读时的书签&#xff0c;可以很轻易找到自己阅读到了哪里。 对于git来说&#xff0c;在使用git对项目进行版本管理的时候&#xff0c;当我们的项目开发到一定的阶段&#xff0c;需要发布一个版本。这时&#xff0c;我们就可以对…

Spring 实战 第六版 学习笔记

Spring 实战 第六版 学习笔记 There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated should leave quickly.…

【C语言督学训练营 第一天】课程导学,编程环境的安装

文章目录前言一、C语言学习常遇到的问题二、程序员职业发展三、C语言简介及环境搭建1.C语言简介2.安装编译器3.windows按装CLion前言 本系列是本人在复习408的时候记录的一些学习笔记&#xff0c;看的课程是王道的课程&#xff0c;只不过加入了一些个人的见解。不得不说王道的…

PTL仓库提货照明解决方案

仓库拣货到光解决方案是一种先进的导光技术&#xff0c;用货架空间上的全套电子显示装置&#xff08;如信号灯、显示器、确认按钮&#xff09;代替拣货单&#xff0c;简化仓储或配送&#xff1b;订单仓库中心履行流程的无纸化、高效且经济高效的解决方案。 什么是按光拣货系统(…

Java——包装类和List及ArrayList

目录 包装类&#xff08;Wrapped Class) 包装类的使用---装箱和拆箱 自动装箱和自动拆箱 Integer的易错题 javap反编译工具 List接口的使用 方法 ArrayList 使用 打印 区别 扩容机制 ArrayList练习 字符集合 杨辉三角 ​编辑 包装类&#xff08;Wrapped Class) Object 引用可…

CSS居中之 { left:50%; top:50%; transform:translate(-50%,-50%); }

CSS居中之 { left:50%; top:50%; transform:translate(-50%,-50%); } left:50%; top:50%; transform:translate(-50%,-50%); left:50%; top:50%; transform:translate(-50%,-50%);也可以写成: left:50%; top:50%; translate: -50% -50%; left:50%; top:50%; translate: -50%…

电子技术——CMOS反相器的动态响应

电子技术——CMOS反相器的动态响应 数字系统的速度&#xff08;例如计算机&#xff09;取决于其构成逻辑门的信号传播速度。因为反相器是数字逻辑门电路的基础&#xff0c;反相器的传播速度是一个很重要的特性。 传播延迟 传播延迟定义为反相器响应他的输入所需要的时间。特…

项目管理报告工具的功能

项目报告软件哪个好&#xff1f;Zoho Projects的项目管理报告工具为您提供整个组织的360可见性&#xff0c;获取所有项目的实时更新&#xff0c;使用强大的项目报告软件推动成功。Zoho Projects的项目报告软件允许团队整理和监控他们的资源和项目&#xff0c;以评估进度并避免对…

例1.10 几何概型题型一——(会面问题)

【例 1.10】&#xff08;会面问题&#xff09;甲乙两人约定在下午6 点到7点之间在某处会面,并约定先到者应等候另一人20 分钟,过时即可离去,求两人能会面的概率。我的答案&#xff1a;一、信息(1)对于甲乙会面约定事件是6~7点。(2)对于规则要求先到者等另一个人20分钟。(3)求两…

SAP会计科目打删除标记及如何物理删除

如果一个科目如果创建错误了&#xff0c;需要删除。如果在FS00上操作&#xff0c;点删除按钮&#xff0c;那么只是打删除标记而已&#xff08;相当于冻结&#xff09;。 删除和打删除标记是不一样的&#xff1a;打删除标记只是锁定该科目不再被用于记账业务&#xff0c;该科目仍…

进程概念~

进程概念 &#xff08;冯诺依曼体系结构&#xff0c;操作系统&#xff0c;进程概念&#xff0c;进程状态&#xff0c;环境变量&#xff0c;程序地址空间&#xff09; 冯诺依曼体系结构&#xff1a;&#xff08;计算机硬件体系结构&#xff09; 输入设备&#xff0c;输出设备&a…

【Java|基础篇】超详细讲解运算符

文章目录1. 什么是运算符2. 算术运算符隐式类型转换强制类型转换字符串的拼接字符相加自增和自减运算符3.赋值运算符4. 关系运算符5. 逻辑运算符短路与(&&)和短路或(||)6.三目运算符7. 位运算符8. 移位运算1. 什么是运算符 运算符用于执行程序代码运算&#xff0c;会针…

OpenCV-PyQT项目实战(11)项目案例07:摄像头操作与拍摄视频

欢迎关注『OpenCV-PyQT项目实战 Youcans』系列&#xff0c;持续更新中 OpenCV-PyQT项目实战&#xff08;1&#xff09;安装与环境配置 OpenCV-PyQT项目实战&#xff08;2&#xff09;QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战&#xff08;3&#xff09;信号与槽机制 …

【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(中)

系列文章目录 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(上) 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(中) 文章目录系列文章目录前言安装OGG12C软件一、Linux本地GUI…

配置本地 python GEE、geemap环境

1.安装anconda 百度搜索anconda清华镜像&#xff0c;从清华镜像中选择最新的anconda安装包&#xff0c;国内镜像网站下载速度较快&#xff0c;如果从国外官网下载速度相当慢&#xff0c;详细安装教程请参考&#xff1a; anconda安装教程https://blog.csdn.net/lwbCUMT/article…

这些Python计算机视觉工具,帮你coding事半功倍

作为开发人员喜爱的语言之一&#xff0c;Python以其丰富的社区可用工具和库而闻名。我们列出了开发人员可以用于计算机视觉10个流行流行的Python库或平台&#xff0c;以帮助开发人员自动化开发任务&#xff0c;其中包括检测和可视化。1 | fastaifastai是一个深度学习库&#xf…

HBase读取流程详解

读流程从头到尾可以分为如下4个步骤&#xff1a;Client-Server读取交互逻辑&#xff0c;Server端Scan框架体系&#xff0c;过滤淘汰不符合查询条件的HFile&#xff0c;从HFile中读取待查找Key。其中Client-Server交互逻辑主要介绍HBase客户端在整个scan请求的过程中是如何与服务…